12

我有一个阻塞套接字(至少它出现在以下代码中):

    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。有任何想法吗?

4

2 回答 2

8

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

从超时到期的那一刻起,connect()就好像在非阻塞套接字上调用一样。

参考这个案例(逐字逐句man connect并忽略下面的“立即”):

进展

套接字是非阻塞的,连接不能立即完成。可以通过选择要写入的套接字来选择(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)、sendmsg(2));超时对 select(2)、poll(2)、epoll_wait(2) 等无效。

没有任何消息,connect()所以我不确定我的答案是否成立。

于 2013-03-06T10:13:17.920 回答
2

试试看if (connect(...) < 0)。您可能根本没有收到错误。

NB 阻塞模式是默认设置。你不必设置它。

于 2013-03-06T20:22:08.387 回答