Socket阻塞和Select超时问题

4
我正在创建一个回显服务器,当客户端闲置时间超过maxWaitTime时,会断开连接。
我希望程序能够阻塞套接字,直到客户端发送数据,但是当我在gdb中运行程序时,它会通过select并在Readline上阻塞。
我知道无论何时经过select时retval = 0,并且fd_set sock变成[256,(31个零)],在select之后,sock变成[32个零]。
连接的接受发生在另一个函数中,并将连接描述符传递给echo函数。
如果您能够帮助我指出正确的方向或让我知道如何在一定时间后断开客户端,请告诉我。
如果您需要更多信息,请告诉我。
提前致谢!
    FD_ZERO(&sock);
    FD_SET(sockfd,&sock);

    int opt = 3;

    setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt));

    timeout.tv_sec = maxWaitTime;
    timeout.tv_usec = 0;

    for ( ; ; ) {
            FD_SET(sockfd,&sock);

            printf("Set is %d\n",FD_ISSET(sockfd,&sock));

            int retval;
            retval = select(1, &sock, NULL, NULL, &timeout);

            if(retval)
            {
                    quitProgram(number);
            }
            else
            {
            printf("n is %d\n",retval);

            if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
            {
                    return;         /* connection closed by other end */
            }

            Writen(sockfd, line, n);

    }

`


如果这是在 POSIX 机器上(例如 OSX 或 Linux),那么 select 的第一个参数应该是最高编号的套接字加一。在你的情况下是 sockfd + 1。另外,我猜你的超时时间 maxWaitTime 不为零? - Some programmer dude
2
非常仔细地阅读select()的手册,有三个重要的事情需要注意:1. select的第一个参数必须是最大的套接字描述符加一;2. 当超时发生时,select返回0;3. 在Linux上,timeout参数会被select()递减 - 因此,如果你在Linux上运行当前代码,它最终将以超时为0的状态运行。 - nos
1
另外,select 在出错时返回 -1,仅在超时时返回零,并且如果套接字已准备好,则返回正数(实际上是三个集合中准备就绪的套接字数量)。因此,您不能仅通过检查返回值是否为非零来判断错误。 - Some programmer dude
1个回答

7
正如其他人所评论的那样,你的代码中存在一些逻辑漏洞。根据你自己的说法:
“我知道每当它经过选择时,retval = 0,fd_set sock变成[256,(31个零)],选择之后,sock变成[32个零]。”
这应该提示你有些地方出了问题。socket在select()退出后不在fd_set中,这意味着socket还不能读取。retval=0表示select()超时了。
每次调用select()时,你不仅要重置fd_set,还要重置timeval。试试这个:
int opt = 3; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt)); 

for ( ; ; )
{ 
    timeout.tv_sec = maxWaitTime; 
    timeout.tv_usec = 0; 

    FD_ZERO(&sock); 
    FD_SET(sockfd,&sock); 

    int retval = select(sockfd+1, &sock, NULL, NULL, &timeout); 
    if (retval <= 0) 
    { 
        quitProgram(number); /* error or connection timed out */
    } 
    else 
    { 
        if ( (n = Readline(sockfd, line, MAXLINE)) <= 0) 
        { 
            return; /* error or connection closed by other end */ 
        } 

        Writen(sockfd, line, n); 
    } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接