c - 多个 select() 来监视多个 FD_SET

问题描述 投票:0回答:3

我不是网络编程专家。我基本上有两种客户,他们有不同的超时时间。我应该使用带有连接套接字的 UDP 来进行客户端-服务器通信。

问题是双重的:

a)无论哪个客户端(或者套接字)在 t1 秒内没有响应,我都需要将其标记为死亡。如果 read_fd_set 中的套接字在超时值内没有任何内容可读取,则使用 select 将会超时。那么,如何使某个相当长一段时间没有数据可读取的套接字超时呢?

  • 目前,每当 select 返回时,我自己都会跟踪哪些套接字正在响应,哪些没有响应。我将 t1.tu_sec 添加到每个客户端(套接字)的单独消耗时间中。然后,我手动关闭并从 FD_SET 中排除在 (n) * (t1.tu_sec) 时间内没有响应的套接字。这是一个足够好的方法吗?

b) 主要问题是有两种客户端具有不同的超时时间,t1 和 t2。我该如何处理这个问题?

  • 我可以在同一个循环中为两种客户端使用两个 select() 吗?没有线程会导致饥饿吗?在这种情况下使用线程是可取的(甚至是必需的)吗?

我已经在网络上漫游多年了!

非常感谢任何帮助。

c sockets posix-select
3个回答
1
投票

这只是一个非常常见模式的特例,其中选择/轮询循环与计时器集合相关联。

您可以使用任务优先级队列,按下一个(绝对)触发时间排序;选择超时始终只是队列前面的绝对时间。

  • 当 select 超时时(并且在下一次迭代之前,如果您的任务可能需要很长时间才能完成),获取当前时间,将应该已经执行的每个任务从队列中拉出,然后执行它
  • (某些)任务需要重新安排,因此请确保在执行此操作时它们可以改变优先级队列

那么你的逻辑就很简单了:

  • 读取时,将套接字标记为忙
  • 在定时器执行时,将套接字标记为空闲
    • 如果它是已经空闲,这意味着自上次计时器到期以来没有收到任何信息:它已经死了

1
投票

我想到的一个快速解决方案是将套接字保留在一个集合中,按剩余时间排序,直到最近的超时。

使用

select
将超时设置为最小剩余时间,从集合中移除/关闭/删除超时套接字,然后重复。

所以,在伪代码中它可能看起来像这样:

C = collection of structs ( socket, timeout, time_remaining := timeout )

while (true) {
    sort_the_collection_by_time_remaining
    next_timeout = min(time_remaining in C)
    select ( sockets in C, next_timeout )
    update_all_time_remaining_values
    remove_from_C_if_required  //if timeout occured
}

0
投票

只需一次

select
调用即可轻松解决。对于每个套接字都有两个与超时相关的值: 实际超时;以及超时之前的时间量。然后每隔 0.1 秒(或类似时间)倒计时“超时时间”,当达到零时关闭套接字。如果套接字在超时之前收到流量,只需将“超时前的时间”重置为超时值,然后再次开始递减计数。

© www.soinside.com 2019 - 2024. All rights reserved.