【问题标题】:Detecting a timed out socket from a set of sockets从一组套接字中检测超时套接字
【发布时间】:2012-12-31 23:38:09
【问题描述】:

我目前正在使用 winsock 构建服务器。我的服务器将处理多个客户端,所以我使用 select() 函数以及读、写和异常集。我已经知道如果一个特定的套接字超时, select() 返回 0 。

但是我如何识别实际超时的套接字呢?

顺便说一句,谁能告诉我 Some_Socket 需要做什么才能使 FD_ISSET(Some_Socket, &Exception) 返回 true?

也许我可以使用上面的函数来检查集合中的每个套接字?

编辑:

假设我有这个例子:

int main(void){

       fd_set rfds;
       struct timeval tv;
       int retval;

       /* Watch stdin (fd 0) to see when it has input. */
       FD_ZERO(&rfds);

       for(int i = 0; i<clientcount; i++) {


        FD_SET(sockets[i].Scksas, &read_mask);

        FD_SET(sockets[i].Scksas, &write_mask);

        FD_SET(sockets[i].Scksas, &excep_mask);

   }

       /* Wait up to five seconds. */
       tv.tv_sec = 5;
       tv.tv_usec = 0;

       retval = select(1, &rfds, NULL, NULL, &tv);
       /* Don't rely on the value of tv now! */

       if (retval == -1)
           perror("select()");
       else if (retval)
           printf("Data is available now.\n");
           /* FD_ISSET(0, &rfds) will be true. */
       else{

           printf("No data within five seconds.\n");

           /*
             Handle timed out socket, but which one ?
           */
       }
       exit(EXIT_SUCCESS);
   }

我应该如何确定哪个 soket 超时?

【问题讨论】:

  • 在下面查看我的答案......简而言之,它们都超时了。也就是说,在您指定的时间内,它们中的任何一个都没有发生任何事情。如果在超时之前其中一个或多个发生了某些事情,那么它将退出选择并返回“有趣”事物的计数,然后您使用 FD_ISSET 遍历它们

标签: c++ windows sockets timeout winsock


【解决方案1】:

问题是您不能使用select 等,因为它们的超时是针对整个集合而不是单个套接字。

有三种简单的解决方案可以找出在特定时间段内没有通信的单个套接字。

  1. 最简单的大概就是为每个socket保留一个结构,并且在这个结构中有个最后通信的时间。您会定期检查所有套接字的这个时间,如果时间太早,则关闭连接。

  2. 另一种解决方案是在协议中添加“保持活动”消息。定期在所有套接字上发送“你还活着吗”消息。如果您在某个超时时间内没有收到“我还活着”的回复,则该连接可能被认为是陈旧的,您可以将其关闭。

  3. 为每个套接字使用单独的线程或进程。然后你可以使用select,因为你的集合中只有一个套接字。

【讨论】:

  • 不回答问题。他在问如何识别这样的套接字。
  • @EJP 用三种识别空闲套接字的方法更新了答案。
  • 很公平,但 keepalive 仍然不是解决方案的一部分:它只是触发解决方案的另一种方式。
【解决方案2】:

更具体地说,如果在指定的超时时间内没有选择任何套接字,select() 返回 0。如果返回为正数,则为设置的套接字数(负返回为选择错误)。知道设置了哪个套接字以及在哪里设置的正确方法是在每个套接字上使用FD_ISSET,例如

if ( 0 != FD_ISSET( sock, &efds ) )...

【讨论】:

  • 请注意,要知道哪个套接字已超时,您需要 (1) 使用 keep-alive 标志,以便报告死掉的套接字; (2) 把 excep_mask 放在 select() 调用中,否则你不会知道它死了。然后你可以在 excep_mask 上测试 FD_ISSET()。
  • 这就是说,这取决于“超时”的含义,如果 5 秒后套接字被认为是无效的,那么你需要一个向量,其中包含最后一次访问套接字的时间。 . 这不仅仅是一个 select() + FD_whatever!
【解决方案3】:

我已经知道如果某个特定的套接字超时,select() 会返回 0。

不,你没有。如果 all 套接字超时,则返回零。在这种情况下,很简单:全部关闭。

如果返回非零,则必须处理读/写 FD 集中的所有 FD;那么您可以处理那些集合中不的所有 FD。您需要维护所有 FD 的最后 I/O 时间,并在该循环中检查是否有任何超过您的超时限制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-08
    • 2011-05-11
    • 1970-01-01
    • 2019-07-11
    • 2015-12-07
    相关资源
    最近更新 更多