【问题标题】:unable to set the timeout for socket connect() call无法设置套接字 connect() 调用的超时时间
【发布时间】:2012-10-10 10:12:14
【问题描述】:

我已经用本机代码编写了客户端套接字程序,并在 android 应用程序中使用它。当服务器不可用时与服务器建立连接时,我遇到了一个奇怪的问题。

当服务器不可用时,客户端 connect() 调用将被折腾,它根本不出来。我试图在互联网上搜索这个。一些链接解释了这些步骤

  1. 将套接字设置为非阻塞模式
  2. 调用连接 - 如果连接成功则很好
  3. 否则将套接字设置回阻塞模式。
  4. 为写入集设置套接字并将其提供给 select() 并要求超时。
  5. 如果选择出来时在写入集中设置了套接字,则连接成功或连接失败。

我尝试了这些步骤,但无论服务器是否正在运行,select() 调用总是只出现超时。我需要你的帮助来解决这个问题。

这是我正在使用的部分代码

bool SocketConnect()
{
   ... Creating the socket ....

   int opts;
   if( (opts = fcntl(clientsocket,F_GETFL) < 0 )
   {
       return false;
   }

   // setting socket to non-block mode
   if( fcntl(clientsocket,opts | O_NONBLOCK) < 0 )
   {
      return false;
   }

   //calling connect
   int ret = connect(clientsocket,(const sockaddr*)&serveraddr,sizeof(serveraddr));
   if( ret < 0 )
   {
       if( errno != EINPROGRESS )
       {
          return false;
       }
   }

   if( ret == 0 )
   {
      //connection successful set the socket to block mode
      fcntl(clientsocket,F_SETFL,opts);
      return true;
   }

   //set the socket to block mode
   if( fcntl(clientsocket,F_SETFL,opts) < 0 )
   {
      return false;
   }

   fd_set writeset;
   FD_ZERO(&writeset);
   FD_SET(clientsocket,&writeset);

   timeval val.
   val.tv_sec = 5;
   val.tv_usec = 0;

   int sret = select(clientsocket+1,NULL,&writeset,NULL,&val);
   if( sret > 0 )
   {
      if( FD_ISSET(clientsocket,&writeset) )
      {
          fcntl(clientsocket,F_SETFL,opts);
          return true;
      }
   }

   return false;
}

当服务器可用时,如果我使用阻塞的连接调用(不使用上述任何步骤),建立连接几乎不需要 1 秒。

如果我使用上述步骤进行连接,则当服务器可用时,如果我给 5 秒时间连接未建立,则事件。事件选择也不等5秒,马上出来返回值0。

请查看此代码,让我知道我在设置 connection() 调用超时时到底哪里出错了..

感谢任何建议或替代方法。

谢谢。

【问题讨论】:

  • 我发现 connect() 上的 linux 文档完全错误。当非阻塞连接()上发生某些事情时,您不会收到写入事件,您会收到一个读取事件 - 即便如此,我似乎还记得一些未发出读取事件的极端情况。 (但请记住,超时的 TCP SYN 可能需要几分钟,超时的 ARP 请求也可能需要几秒钟 - 在很多情况下 TCP/IP 堆栈无法在 connect() 上提供近乎即时的反馈)

标签: c sockets connection


【解决方案1】:

使用闹钟中断连接。这是示例代码

#define CONNECT_TIMEOUT 4

static void AlarmHandler(int sig)
{
sTimeout = 1; 
}
.
.
.
signal(SIGALRM, AlarmHandler); 
sTimeout = 0; 
alarm(CONNECT_TIMEOUT); 
if ( connect(sock, (struct sockaddr *) &server, sizeof(server)) ) 
{ 
if ( sTimeout ) {
NSLog(@"timeout connecting stream socket"); //If connect will remain blocked for 4 seconds after 4 seconds this condition will be triggered
}
}

【讨论】:

    【解决方案2】:

    对于处于非阻塞模式的情况,我看不到您在哪里等待连接完成。

    另外,我想问一下,在建立连接之前,应用程序是否应该做其他事情?如果是这样,我会考虑将 SocketConnect 函数重组为使用 pthreads 之类的单独线程。如果您的应用程序的行为完全取决于客户端连接,我会考虑在连接之前将套接字从非阻塞切换到阻塞,并在 SocketConnect 中保持对连接的调用。

    【讨论】:

    • 他在非阻塞模式下调用connect(),导致connect()立即返回,并将连接完成(或超时)推迟到select()调用
    • 您好,感谢您的回复。我以其他方式解决了这个问题。现在我正在使用 setsockopt 设置读写操作的超时时间。如果服务器在超时时间内没有响应,现在连接就会出现...... :-)
    猜你喜欢
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2012-11-12
    • 2011-06-25
    • 2012-11-26
    • 1970-01-01
    相关资源
    最近更新 更多