零超时的非阻塞 connect() 和 select() 返回 0

non-blocking connect() and select() with zero timeout is returning 0

我正在编写一个单线程应用程序,它可以循环处理多个连接的 TCP 套接字。 这是它启动连接的部分:

// Set up connecting socket
wire[wi].skt=socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,IPPROTO_TCP);
if (wire[wi].skt==-1) return TEC_SOCK_ERR;
wire[wi].sai.sin_family=AF_INET;
memmove(&wire[wi].sai.sin_addr,&rconf.txaddr,sizeof(struct in_addr));
wire[wi].sai.sin_port=htons(rconf.txport);
// Initiate connection
int cres = connect(wire[wi].skt,(struct sockaddr *)&wire[wi].sai,sizeof(struct sockaddr_in));
// Comprehend results
if (cres==0)
{   // Connect already established
    wire[wi].state=CONNECTED;
    return 0;
};
if (cres==-1) // Socket error meaning depends on errno
    switch (errno)
    {
        // This is OK for non-blocking sockets
        case EINPROGRESS : {    // Connect initiated
                                wire[wi].state=CONNECTING;
                                return 0;
                            };
        default : return TEC_SOCK_ERR;
    };
return 0; // Should not normally happen

显然,EINPROGRESS 是最常见的情况,因此循环中还有另一个代码

            case CONNECTING :   {
                                    struct timeval tv;
                                    fd_set rfds;
                                    FD_ZERO(&rfds);
                                    FD_SET(wire[wc].skt,&rfds);
                                    memset(&tv,0,sizeof(struct timeval));
                                    int retval = select(1,NULL,&rfds,NULL,&tv);
                                    printf("%d:%d ",retval,errno);
                                    fflush(stdout);
                                    // Done
                                    break;
                                };

我不明白的是为什么select这里总是returns0和EAGAIN,不管连接是否成功。

我正在寻找最可靠的方法来判断非阻塞套接字上的连接是否(不)成功。 提前致谢。

更新。似乎没有明显的错误,所以我会做一个 MWE 最终在其他地方找到它作为愚蠢的东西:)

您没有打电话给 select() 'regardless of whether the connection was successful or not'。您只在 EINPROGRESS 案例中调用它。如果它 returns 为零,则没有 FD 准备就绪,因此连接仍在进行中。

      int retval = select(1,NULL,&rfds,NULL,&tv);

select的第一个参数不是fds的数量,而是(来自linux手册页):

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

除非您的套接字有 fd 0(在这种情况下您必须关闭标准输入),否则您使用的值 1 是错误的。这意味着集合中所有小于 nfds(即 none)的 fds 都准备就绪,因此 select returns 0。代码应该改为:

       int retval = select(  1+wire[wc].skt,  NULL,&rfds,NULL,&tv);

I'm in a search for the most reliable way of telling if a connection was (not)successful on non-blocking socket.

在套接字上做一个recv。如果已连接,recv 将 return -1,如果没有可读取的内容,您将获得 EAGAIN。如果连接不成功,recv 将 return 0.