对非阻塞套接字使用select()总是返回1

Dar*_*son 5 c sockets select nonblocking

这个问题与(非常接近)在非阻塞套接字连接中,select()始终返回1;但是,我似乎找不到我的代码步履蹒跚的地方。

我正在使用非阻塞套接字,并且想在将客户端连接到服务器以检查超时/成功时使用select()。问题是select()几乎总是立即返回1,即使我什至没有服务器在运行,也没有什么可连接的。预先感谢您的帮助,代码片段如下:

//Loop through the addrinfo structs and try to connect to the first one we can
for(p = serverinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
    {
        //We couldn't create the socket, try again
        perror("client: socket");
        continue;
    }

    //Set the socket to non-blocking
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        //The error was something other than non-block/in progress, try next addrinfo
        if(errno != EINPROGRESS) 
        {
            close(sockfd);
            perror("client: connect");
            continue;
        }

        fd_set write_fds;
        FD_ZERO(&write_fds);            //Zero out the file descriptor set
        FD_SET(sockfd, &write_fds);     //Set the current socket file descriptor into the set

        //We are going to use select to wait for the socket to connect
        struct timeval tv;              //Time value struct declaration
        tv.tv_sec = 5;                  //The second portion of the struct
        tv.tv_usec = 0;                 //The microsecond portion of the struct

        //DEBUG: This is ALWAYS 1
        int select_ret = select(sockfd + 1, NULL, &write_fds, NULL, &tv);
        cout << select_ret << endl;

        //Check return, -1 is error, 0 is timeout
        if(select_ret == -1 || select_ret == 0)
        {
            //We had an error connecting
            cout << "Error Connecting\n";
            close(sockfd);
            continue;
        }
    }

    //We successfully connected, break out of loop
    break;
}
Run Code Online (Sandbox Code Playgroud)

Amb*_*jak 4

您期望select() 返回什么?考虑一下 select() 通常用于等待多个文件描述符 - 如果您连接两个文件描述符,您如何纯粹根据 select 的返回值知道哪一个成功/失败?显然你不会。

这就是为什么 select() 只是告诉您哪些文件描述符以某种方式发生了更改,并且您应该独立确定那是什么。对于 connect(),您应该调用 getsockopt() 来检索连接尝试的结果。请参阅此答案,其中我解释了如何执行非阻塞 connect()。

  • @EJP 我很想知道你在谈论什么文档。Linux connect(2) 手册页中的官方方法是 getsockopt(fd, SOL_SOCKET, SO_ERROR, ...) 我知道这是因为我写了手册页的这一部分。很久以前,我使用“再次连接”方法编写了一个程序。它对我有效,但对 BSD 用户不起作用,他们坚持认为第二次连接是一个愚蠢的仅限 Linux 的事情。 (5认同)