2013-03-06 86 views
6

我有一个阻挡插座(至少它,以便将出现在下面的代码):connect()返回阻塞套接字上的“正在进行中的操作”?

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (sock < 0) { 
      ERROR("%s: error opening socket", __func__); 
      return (RESP_ERROR); 
    } 

    t.tv_sec = timeout; 
    t.tv_usec = 0; 

    int rf = fcntl(sock, F_GETFD); 
    ERROR("fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK); 

    if ((setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&t, sizeof (t)) < 0) 
     || (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&t, sizeof (t)))) { 
      strerror_r(errno, err, 254); 
      ERROR("%s: error on setsockopt -> %s", __func__, err); 
      close(sock); 
      return (RESP_ERROR); 
    } 

    rf = fcntl(sock, F_GETFD); 
    ERROR("after select fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK); 

    if (connect(sock, (struct sockaddr *)&dst, sizeof (dst)) != 0) { 
      strerror_r(errno, err, 254); 
      ERROR("%s: error on connect -> %s", __func__, err); 
      close(sock); 
      return (RESP_ERROR); 
    } 

这是从日志:

03月06日10时42分04秒的TcpClient:RET的fcntl = 0 ,RET & O_NONBLOCK = 0

03月06日10时42分04秒的TcpClient:后选择的fcntl RET = 0,保留& O_NONBLOCK = 0

03月06日十点42分14秒的TcpClient :验证:错误连接 - >正在进行的操作

看来这是一个阻塞的套接字,但返回非阻塞的典型错误? Linux是2.6.18-308.el5。有任何想法吗?

+1

'timeout'有哪个值? – alk 2013-03-06 10:04:23

+0

为了验证我的答案,我想做一些测试。因此,我想知道'dst'在传递给connect()之前如何被初始化。你确定它的成员'sin_family'已经设置正确吗? – alk 2013-03-07 07:24:18

回答

4

如果timeout不是0调用connect()超时并返回。这与连接是否建立无关。

从超时过期connect()的行为就像在非阻塞套接字上调用一样。

参照这种情况下(从逐字和man connect忽略 “立即” 下面):

EINPROGRESS

插座是非阻塞和连接不能立即完成。可以通过选择用于写入的套接字来选择(2)或轮询(2)来完成。 select(2)指示可写性后,使用 getsockopt(2)读取SOL_SOCKET级别的SO_ERROR选项以确定connect()是否成功完成(SO_ERROR为零)或不成功(SO_ERROR是此处列出的常见错误代码之一, - 失败的原因)。


BTW:可能有人证实这是标准的行为,并为此明确某处提到?

man 7 socket状态(以斜体字我):

SO_RCVTIMEO和SO_SNDTIMEO

指定接收或发送超时,直到报告错误。如果没有数据传输并且超时已经达到,则返回-1,并将errno设置为EAGAIN或EWOULDBLOCK ,就好像套接字是 指定为非阻塞。 [...]超时只对执行套接字I/O(例如read(2),recvmsg(2),send(2), sendmsg(2))的系统调用有效。超时有选择(2),轮询(2),epoll_wait没有影响(2)等

没有关于connect()所以我不能确定我的回答也持有字。

+0

它出现“从超时过期的那一刻起,connect()的行为就好像在非套接字套接字上调用一样。”这是关键部分。关闭(袜子)停止此操作? – 2013-03-06 10:19:30

+1

确实'关闭()'无效套接字。然而操作系统可能会在地址:端口上持续一段时间。要在操作系统释放之前重新调用地址:端口,您可以指定套接字选项“SO_REUSEADDR”。 – alk 2013-03-06 10:21:21

+0

我不明白为什么设置读取或写入超时会影响connect()。我知道获取超时连接的唯一方法是使用select()以非阻塞模式进行连接。 – EJP 2013-03-06 20:23:45

0

尝试'if((connect(...))< 0)'。你可能没有得到任何错误。