0

我正在使用 libevent 为网络程序编程。

在这个程序中,我想使用 libpcap 捕获数据包,修改这些数据包,然后将它们发送出去。这些步骤应该是实时的。

所以我创建了一个实时捕获,使用 pcap_get_selectable_fd 获取pcap_fd实时捕获的文件描述符并将 READ_EV 事件添加pcap_fd到 libevent 循环。无论如何,这就像 select() 或 epoll() 轮询文件描述符。

但是我注意到程序没有按预期运行,所以我使用 tcpdump 和一些调试日志来检查问题。我注意到有时,轮询pcap_fd无法正常工作,例如,在开始时,它似乎工作正常。一段时间后,READ_EV 事件在pcap_fd2 秒后触发,这确实是一个很大的延迟。

我读了手册,上面写着:

   pcap_get_selectable_fd(3) will return a file descriptor. But simple select() 
   or poll() will not indicate that the  descriptor  is  readable
   until  a  full  buffer's worth of packets is received, even if the read
   timeout expires before then.  

在我看来,实时捕获已捕获大约 15 个数据包(每个数据包为 66 个字节),但 READ_EV 事件直到 2 秒后才会触发。但在一开始,即使 1 个数据包到达也可能触发 READ_EV 事件。这意味着它非常不稳定。

   To work around this, an application  that
   uses  select()  or  poll()  to  wait for packets to arrive must put the
   pcap_t in non-blocking mode, and must  arrange  that  the  select()  or
   poll()  have a timeout less than or equal to the read timeout, and must
   try to read packets after that timeout expires, regardless  of  whether
   select() or poll() indicated that the file descriptor for the pcap_t is
   ready to be read or not.

我的问题是针对上面的段落:

1 在我看来有2个超时,一个读取超时和一个自己定义的超时,那么什么是读取超时呢?

2 在我看来,我需要设置一个非常小的超时并使用pcap_next()or轮询实时捕获pcap_dispatch,对吗?那么我的轮询可能会非常消耗 CPU?

谢谢!</p>

4

1 回答 1

1

有问题的段落可能是

请注意,在大多数 BSD 的大多数版本(包括 Mac OS X)上,select() 和 poll() 不能在 BPF 设备上正常工作;pcap_get_selectable_fd() 将在大多数版本(FreeBSD 4.3 和 4.4 除外)上返回文件描述符,即使在 pcap_open_live() 中指定的超时到期后,简单的 select() 或 poll() 也不会返回。为了解决这个问题,使用 select() 或 poll() 等待数据包到达的应用程序必须将 pcap_t 置于非阻塞模式,并且必须安排 select() 或 poll() 的超时时间小于或等于 pcap_open_live() 中指定的超时,并且必须在超时到期后尝试读取数据包,无论 select() 或 poll() 是否指示 pcap_t 的文件描述符已准备好被读取。(该变通方法在 FreeBSD 4.3 及更高版本中不起作用;然而,在 FreeBSD 4.6 及更高版本中,select() 和 poll() 在 BPF 设备上正常工作,因此该变通方法不是必需的,尽管它没有害处。)

你没有引用第一句话,这在这里很重要——你说的是“epoll()”,这是一个 Linux 系统调用;该段不适用于 Linux。

(该段落的当前版本,位于 pcap_get_selectable_fd 手册页中,是

   Note that in:

          FreeBSD prior to FreeBSD 4.6;

          NetBSD prior to NetBSD 3.0;

          OpenBSD prior to OpenBSD 2.4;

          Mac OS X prior to Mac OS X 10.7;

   select()   and   poll()   do   not   work  correctly  on  BPF  devices;
   pcap_get_selectable_fd() will return a file descriptor on most of those
   versions  (the  exceptions  being  FreeBSD  4.3  and 4.4), but a simple
   select() or poll() will not indicate that the  descriptor  is  readable
   until  a  full  buffer’s worth of packets is received, even if the read
   timeout expires before then.  To work around this, an application  that
   uses  select()  or  poll()  to  wait for packets to arrive must put the
   pcap_t in non‐blocking mode, and must  arrange  that  the  select()  or
   poll()  have a timeout less than or equal to the read timeout, and must
   try to read packets after that timeout expires, regardless  of  whether
   select() or poll() indicated that the file descriptor for the pcap_t is
   ready to be read or not.  (That workaround will not work in FreeBSD 4.3
   and  later; however, in FreeBSD 4.6 and later, select() and poll() work
   correctly on BPF devices, so the workaround isn’t  necessary,  although
   it does no harm.)

哪个更正确。但是请注意,由于 Mac OS X 10.6 的 BPF 中的一个错误,非阻塞模式无法正常工作,因此该解决方法也不适用于 OS X 10.6。在 10.7 及更高版本中不需要。)

如果您使用的是 libevent,则应使用( NOT an !) 将其pcap_fd置于非阻塞模式,并且如果您收到事件,则使用它来处理数据包。pcap_setnonblock()fcntl()READ_EVpcap_dispatch()

于 2013-11-07T12:32:18.003 回答