【问题标题】:Detecting the timed out client in select function在选择功能中检测超时客户端
【发布时间】:2013-11-13 08:26:57
【问题描述】:

我想使用select 函数来处理不同的文件描述符。当程序启动时,它必须按照一个时间间隔开始向其他客户端发送数据包。我的第一个问题是如何在主 while 循环中使用计时器而不中断 while 循环和 select 函数的功能?那是因为我需要在计时器运行时接受用户输入。

第二个问题是,如果我需要将 send 函数放在我的 while 循环中,我现在不需要。程序进入while循环时需要写send函数还是需要在其他地方使用?

此外,程序必须检测在特定时间未激活的文件描述符。如何检测哪些文件描述符没有向服务器发送任何数据包?

您可以在下面看到我到目前为止编写的代码。你能帮我修一下吗? 我还没有在这里使用任何计时器。此外,程序无法检测到哪个文件描述符已超时。

        FD_ZERO(&masterfds);
        FD_SET(udp_con, &masterfds);
        maxfds = udp_con;

        while(exit == false)
        { //Do I need to use the send function here?
            FD_ZERO(&readfds);
            readfds = masterfds;

            selectFunc = select(maxfds+1, &readfds, NULL, NULL, &tv);
            if(selectFunc < 0)
            {
                message("error in select");
                exit = true;
            }
            else if(selectFunc == 0)
            { //How can I detect which file descriptor is timed out?
                for(i = 0; i <= maxfds; i++)
                {
                    if(FD_ISSET(i, &readfds))
                    {
                        //Doesn't work
                        cout<<"The file descriptor "<<i<<" has timed out"<<endl;
                    }
                }
            }
            else
            { //The server has received something from a client

                for(i = 0; i <= maxfds; i++)
                {

                }
            }
        }

【问题讨论】:

    标签: c++ sockets network-programming udp posix-select


    【解决方案1】:

    select 的最后一个参数是等待文件描述符集中事件的时间量。您可以使用它来等待事件的预定义时间段,例如 100 毫秒。如果超时没有收到任何事件,则 select 将返回 0 并且不会设置描述符。

    现在您需要从服务器的角度考虑“活动”连接的含义。通常,您应该为每个 fd 在该连接上上次接收数据的时间保留一个单独的时间戳。发送可以毫无问题地进行,并不表示连接仍处于活动状态。

    所以代码应该是这样的结构——一些粗略的伪代码:

    select with timeout
    did select return 0:
      (this means that no data was received for the timeout on any descriptor)
      (this is the place to check if any descriptor went past its 'active' limit)
      iterate over all fds:
        if last_received_timestamp[current_fd] + deadline > current_time:
          remove fd or do something else
    else:
      (there is something to read)
      iterate over descriptors in readfds:
        read data and process it
        last_received_timestamp[current_fd] = current_time
    

    希望这会有所帮助。

    附加信息:

    如果您想要更统一的方式来处理这个问题,请尝试查看 timerfd_create。这可用于创建看起来像文件描述符的计时器,因此您可以为它们使用 select 以获取某些事件的通知。例如,您可以为您拥有的每个普通 fd 创建一个这样的 timerfd,并将其设置为在达到最后期限时过期。这里的关键是在收到数据时重新启动计时器。

    像这样等待事件然后按顺序处理所有事件的单线程循环的一个典型问题是,如果服务器变得太忙或连接的数据处理时间过长,所有连接都会出现延迟。更好的架构是使用线程池来处理套接字上的读/写。这释放了事件循环并为所有客户端提供了更好的响应时间。但是,这更复杂,可能超出了您想要实现的范围。

    【讨论】:

    • 谢谢,但我想知道,因为我使用的是 UDP 连接,并且我不使用接受函数为每个客户端获取新的文件描述符,我是否需要向我的主FD列表?我现在有点困惑。看来我要使用的唯一文件描述符是“udp_con”。对吗?
    • 我正在使用 linux,只是尝试包含头文件“sys/timerfd.h”,但找不到任何具有该名称的头文件。如何在 linux 中利用 timerfd?
    猜你喜欢
    • 1970-01-01
    • 2018-02-21
    • 2013-11-16
    • 2012-12-06
    • 2012-01-10
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    相关资源
    最近更新 更多