【问题标题】:Winsock - Select's timeout on Listening socket causing every subsequent Select call to failWinsock - Select 在侦听套接字上的超时导致每个后续 Select 调用失败
【发布时间】:2014-02-13 01:00:28
【问题描述】:

我想先说我的问题已通过将 Select() 的超时选项设置为 NULL 来完全解决。

但我想使用超时,所以这是我的问题。服务器程序非常简单明了,它侦听连接,接受它们并打印到控制台。

问题是,在 select 的第一次超时后,select 将返回 -1(MSDN 几乎没有提供关于什么会导致从 select() 返回 -1 的文档,只是它是一个错误信号) 并有效地停止来自程序的任何更多通信。

服务器 - main.cpp

int main(){

    /* variables */
    int iResult, iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
    bool exit=false;
    int foundRoom, tempFoundRoom;
    fd_set readfds, writefds;
    struct timeval tv;
    long double counter=0;
    int maxfd=0;

    /* Server variables */
    WSADATA wsaData;
    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL;
    struct addrinfo hints;


    printf("~SERVER~\n");

     /* Initialize Winsock*/
    initialize_winsock(wsaData, hints, &result);

    /* Set socket and bind to TCP listening socket */
    set_socketandbind(ListenSocket, result, maxfd);

    //non-blocking mode
    u_long iMode=1;
    ioctlsocket(ListenSocket,FIONBIO,&iMode);
    ioctlsocket(ClientSocket,FIONBIO,&iMode);

    // clear the set ahead of time
    FD_ZERO(&readfds);
    //FD_ZERO(&writefds);

    //add our descriptors to the set
    FD_SET(ListenSocket, &readfds);

    //wait until either socket has data ready to be recv()d (timeout 5 secs)
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    /* main loop */
    for(;;){
        cout << "Maxfd: " << ListenSocket << " \ " << maxfd << endl;

        //select
        int rv = select(ListenSocket+1, &readfds, NULL, NULL, &tv);

        cout << "Updateing... rv: " << rv << endl;

        if (rv == -1) {
            perror("Select: "); // error occurred in select()
        }else if (rv == 0){
            printf("Timeout occurred! No data after 5 seconds.\n");
        }else{

            // one or both of the descriptors have data
            if (FD_ISSET(ListenSocket, &readfds)) {

                // Accept a client socket
                ClientSocket=accept(ListenSocket, NULL, NULL);

                cout << "Connected a user." << endl;

            }

            counter++;
        }

        cout << endl;
        Sleep(500);

    };

    /* Unset server socket */
    closesocket(ListenSocket);

    system("pause");
    return 0;
}

输出应该是,超时,超时,超时,因为这就是 select() 应该如何工作,以及它如何在我的客户端上工作。而是输出超时,错误,错误,错误:

【问题讨论】:

    标签: c++ sockets networking network-programming winsock


    【解决方案1】:

    每次循环时,您都需要重置“TV”和 FD 结构。

    【讨论】:

    • 你的意思是每次调用 select() 都会重置电视结构?
    • 这实际上并没有解决问题。我需要在循环中添加 FD_ZERO 和 FD_SET 并重置电视,而不仅仅是在每个循环中添加电视。这是为什么呢?
    • 因为 select() 改变了 FD 结构。如果超时,说明什么都没有准备好,所以相应的位被清除了,所以你需要重置它。
    • 我实际上是误会了,但现在我很确定我知道 100% 的问题和解决方案。当 select() 对特定套接字超时时,该 fd 中的套接字(即:readfds)被删除,因此当它超时时,它删除了 fd 中唯一的套接字。由于 fd 中没有更多的套接字,它别无选择,只能返回错误,因为没有要检查的套接字。解决方案是 FD_SET 在 fd 中的套接字(即:readfds)再次超时,例如为了可读性。现在完美运行,谢谢!
    • 这正是我刚才所说的。
    猜你喜欢
    • 2017-07-23
    • 1970-01-01
    • 2014-08-11
    • 2019-05-30
    • 1970-01-01
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    相关资源
    最近更新 更多