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

时间:2015-04-13 10:07:02

标签: c sockets tcp posix nonblocking

我正在编写一个单线程应用程序,在循环中无需多个连接的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总是返回0和EAGAIN,无论连接是否成功。

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

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

3 个答案:

答案 0 :(得分:1)

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

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

  

nfds是三组中任何一组中编号最高的文件描述符,加上1。

除非你的套接字有fd 0(在这种情况下你必须关闭stdin),你使用的值1是错误的。这意味着集合中小于nfds(即无)的所有fds都已准备好,因此选择返回0.代码应该是:

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

答案 1 :(得分:0)

无论连接是否成功,您都不会调用select()'。你只是在EINPROGRESS案中调用它。如果它返回零,则没有FD就绪,因此连接仍在进行中。

答案 2 :(得分:0)

  

我正在寻找一种最可靠的方式来判断连接在非阻塞套接字上是否成功。

在套接字上执行recv。如果已连接,recv将返回-1,如果没有任何内容可读,您将获得EAGAIN。如果连接不成功,recv将返回0.

相关问题