0

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

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

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

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

        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++)
                {

                }
            }
        }
4

1 回答 1

0

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,并将其设置为在达到最后期限时过期。这里的关键是在收到数据时重新启动计时器。

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

于 2013-11-02T12:13:10.637 回答