【问题标题】:Socket Blocking and Timeout on Select选择时的套接字阻塞和超时
【发布时间】:2012-09-26 12:50:36
【问题描述】:

我目前正在创建一个回显服务器,该服务器会在空闲的 maxWaitTime 时间后断开客户端的连接。

我希望程序会阻塞套接字,直到客户端发送数据,但是当我在 gdb 中运行程序时,它会通过选择并阻塞 Readline。

我知道 retval = 0 每当它通过 select 并且 fd_set sock 变为 [256, (31 zeroes)] 并且在 select 之后,sock 变为 [32 zeroes]。

连接的接受发生在另一个函数中,连接描述符被传递给 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 是非零的?
  • 仔细阅读 select() 的手册页。 3 件重要的事情是: 1. select 的第一个参数必须是最大的套接字描述符加一个 2. select 在超时发生时返回 0。 3. 在 Linux 上,超时参数由 select() 递减 - 因此,如果您在 Linux 上,您当前的代码最终将以 0 的超时时间运行
  • 另外一点,select 在错误时返回 -1,仅在超时时返回零,如果套接字已准备好,则返回正数(实际上是三组中准备好的套接字数)。所以你不能只检查返回值是否为非零错误。

标签: c sockets select


【解决方案1】:

正如其他人所评论的那样,您的代码中存在一些逻辑漏洞。您自己承认:

我知道 retval = 0 每当它通过 select 并且 fd_set sock 变为 [256, (31 zeroes)] 并且在 select 之后,sock 变为 [32 zeroes]。

这应该向您表明出了点问题。在select() 退出后,该套接字不在fd_set 中,这意味着该套接字尚不可读。 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); 
    } 
}

【讨论】:

  • 谢谢!正是我想要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 2011-02-27
  • 1970-01-01
  • 2020-10-30
相关资源
最近更新 更多