【问题标题】:How to get timestamp at which a file descriptor monitored by select() becomes ready?如何获取 select() 监视的文件描述符准备就绪的时间戳?
【发布时间】:2016-05-10 23:56:59
【问题描述】:

我的 C 程序使用 TCP 套接字 进行通信。

我正在使用迭代服务器和select() 来监听多个文件描述符;每个客户端一个 TCP 套接字文件描述符。

有没有一种方法,我可以使用它来确定文件描述符何时准备就绪?

该应用程序适用于 linux 平台。

应用程序是这样的:

我有一组文件描述符 {fd1, fd2, ... fdN}

while (True)
     S <-- select (fd1, fd2, ... fdN)  // Set S contains the ready fds

     S = {fd1, fd2, fd3}.
     /* Say only the file descriptors fd1, fd2 and fd3 are ready.
      * I want to process in FIFO order.
      * Hence, I need timestamp at which a file descriptor became ready.*/

     process (S)   /* It may take 2-3 minutes. Which is not negligible. 
                    * Say t units for generalization.*/

注意,由于处理文件描述符需要t个单位,所以集合S中两个文件描述符的就绪时间之间的最大差异 可以是 t 个单位。

因此,文件描述符准备就绪的时间变得很重要。

我想知道如何获得文件描述符准备就绪的时间戳

【问题讨论】:

  • @LPs 你在说什么?每个接受的连接都以新套接字的形式返回。
  • @LPs 没有理由相信 OP 会这样做——而且无论哪种方式,它都可能与问题无关。根据描述,他正在以非常标准和直接的方式实现带有 select() 循环的服务器。 accept() 创建一个文件描述符,每个客户端都有一个。
  • @LPs 如果有没有accept()connect() 使用TCP 套接字的方法,我在30 年的网络编程中还没有遇到过。
  • @EJP 我的错。我说的是 UDP 套接字(SOCK_DGRAM)。
  • 大家好。抱歉,迟到的评论。我的问题的一个例子:假设文件描述符 fd1fd2 已经准备好。现在我调用select()。它会返回说 fd1fd2 准备就绪。有没有办法找出哪个文件描述符首先准备好?文件描述符的数量可以超过 2 个

标签: c linux sockets select tcp


【解决方案1】:

正如@EJP 已经解释的那样,select 将在数据到达几纳秒后返回。然后由您决定调用 gettimeofday() 或类似的方法来获取当前时间。

如果您需要避免为每个数据包调用 gettimeofday() 的开销,您可以尝试一下 libevent,因为它支持缓存的 gettimeofday()(根据您的数据包处理程序运行的时间长短有一点增量)。有关 event_base_gettimeofday_cached() 的更多信息,请参阅 http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html

如果您确实需要尽可能高精度的帧到达时间,您可以切换到 libpcap、DPDK 或 netmap。它们提供帧到达的时间戳 - 缺点是您需要自己处理整个 IP/TCP 堆栈(您可以使用 lwip 或 libnids)。

【讨论】:

  • 说文件描述符 fd1fd2 已经准备好了。现在我调用select()。它会返回说 fd1fd2 准备就绪。有没有办法找出哪个文件描述符首先准备好?文件描述符的数量可以超过 2 个
  • 为什么获得订单如此重要?如果您通过网络运行框架,您会看到一堆可能添加一些(最小)延迟的设备。目的是什么?
  • @ hecke 我为我的问题添加了更多描述。请参考相关性。
  • @Kulwant - 因为我无法在下面评论您自己接受的答案:在套接字上使用 fstat() 给我零 - 对于 st_[amt]_ti​​me。即使这行得通——它也会给你以秒为单位的时间。第二个是......年龄如果你处理网络。上面的问题针对您的用例原因,也许您可​​以切换到另一个架构来实现您的要求。
  • 我刚查了Linux 3.16的源码。如果创建了一个套接字 (net/socket.c),作为该过程的一部分,一个新的伪 Inode 将被实例化。之后,inode->i_op 设置为 sockfs_inode_ops - 但这仅包含 getxattr 和 listxattr - getattr 未设置。但是 stat (fs/stat.c) 需要 getattr - 否则统计信息不会更新。这解释了为什么 fstat() 在套接字上成功 - 但它永远不会提供任何更新的统计信息(至少如果您运行 Linux 内核)。
【解决方案2】:

套接字在select() 返回前几纳秒就准备好了。 现在已经准备好了。select() 不会等待一堆套接字准备好。

【讨论】:

  • select 的第一个参数指定要等待的文件描述符的数量。 select 的唯一目的是等待多个文件描述符。如果你只想等待一个文件描述符,你可以使用read
  • @ceving select的第一个参数是你要等待的最后一个文件描述符的最大数字+1。
  • @ceving select 等待任何一个文件描述符准备好;它不会等待 all 文件描述符准备好。 (它可以报告多个 fds已经准备好,如果它们几乎同时准备好,或者如果它们在你调用@987654327之前就已经准备好了@. 但是,同样,它不会等待所有事件。没有系统调用来等待所有 N 个事件。)
  • @zwol 我说了什么不同的吗?也许我错过了提问者错过了理解的内容。
  • @ceving 我想是我误会了。我以为你是说调用select 是没有意义的,除非你想等到所有 N 个 fds 都准备好,这当然不是它的作用。
【解决方案3】:

文件描述符准备就绪的时间戳是文件描述符的修改时间。 或者换句话说,文件描述符所代表的文件最后一次修改的时间。

可以使用 fstat() 方法获取文件的修改时间(由文件描述符表示)。 阅读http://pubs.opengroup.org/onlinepubs/009695399/functions/fstat.html了解详情。

【讨论】:

  • 有趣。从技术上讲,这是针对 file 的。 TCP 套接字不是文件。这似乎是一个不可移植的解决方案。
  • 在套接字上下文中(按照 OP 的要求),这个答案是错误的。看我的评论above
猜你喜欢
  • 2019-10-16
  • 1970-01-01
  • 2021-03-29
  • 2023-03-11
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多