connect() 在阻塞套接字上返回“操作正在进行中”?
Posted
技术标签:
【中文标题】connect() 在阻塞套接字上返回“操作正在进行中”?【英文标题】:connect() returns "Operation now in progress" on blocking socket? 【发布时间】:2013-02-21 01:05:47 【问题描述】:我有一个阻塞套接字(至少在下面的代码中是这样):
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);
这是来自日志:
3 月 6 日 10:42:04 tcpclient: fcntl ret=0, ret & O_NONBLOCK = 0
3 月 6 日 10:42:04 tcpclient: 在选择 fcntl ret=0, ret & O_NONBLOCK = 0 之后
3 月 6 日 10:42:14 tcpclient: authenticate: error on connect -> 操作正在进行中
这似乎是一个阻塞套接字,但返回非阻塞的典型错误? Linux 是 2.6.18-308.el5。有什么想法吗?
【问题讨论】:
timeout
有哪个值?
为了验证我的答案,我想做一些测试。因此,我想知道dst
在传递给connect()
之前是如何初始化的。你确定它的成员sin_family
设置正确吗?
【参考方案1】:
如果timeout
不是0
,则对connect()
的调用超时并返回。这与是否建立连接无关。
从超时到期的那一刻起,connect()
的行为就像在非阻塞套接字上调用一样。
引用此案例(逐字逐句来自man connect
并忽略下面的“立即”):
EINPROGRESS
套接字是非阻塞的,连接不能立即完成。可以通过选择要写入的套接字来选择(2)或轮询(2)来完成。在 select(2) 表示可写后,使用 getsockopt(2) 读取 SOL_SOCKET 级别的 SO_ERROR 选项,以确定 connect() 是成功完成(SO_ERROR 为零)还是未成功完成(SO_ERROR 是此处列出的常见错误代码之一,请解释- 失败的原因)。
顺便说一句:有人可以确认这是标准行为,并且在某处明确提到了吗?
man 7 socket
状态(我的斜体):
SO_RCVTIMEO 和 SO_SNDTIMEO
指定接收或发送超时直到报告错误。 [...] 如果没有数据被传输并且已经达到超时,则返回 -1 并将 errno 设置为 EAGAIN 或 EWOULDBLOCK ,就像套接字是 指定为非阻塞。 [...] 超时仅对执行套接字 I/O 的系统调用有效(例如,read(2)、recvmsg(2)、send(2)、 发送消息(2));超时对 select(2)、poll(2)、epoll_wait(2) 等无效。
没有关于connect()
的消息,所以我不确定我的回答是否成立。
【讨论】:
它显示“从超时过期的那一刻起,connect() 的行为就像在非阻塞套接字上调用一样。”这是关键部分。 close(sock) 会停止这个操作吗? 当然close()
使套接字无效。但是,操作系统可能会在一段时间内保留地址:端口。要在操作系统发布之前恢复地址:端口,您可以指定套接字选项SO_REUSEADDR
。
我不明白为什么设置读取或写入超时会影响 connect()。我知道获得超时连接的唯一方法是使用 select() 在非阻塞模式下进行。【参考方案2】:
试试if (connect(...) < 0)
。您可能根本没有收到错误消息。
NB 阻塞模式是默认设置。您不必设置它。
【讨论】:
以上是关于connect() 在阻塞套接字上返回“操作正在进行中”?的主要内容,如果未能解决你的问题,请参考以下文章