2013-06-28 60 views
0

我編程使用libevent的網絡程序返回的文件描述符的實時使用。的libpcap:由pcap_get_selectable_fd

在這個程序中,我想捕捉使用libpcap的數據包,修改這些數據包,然後發送出去。這些步驟應該是實時的。

所以我創建了一個實時捕捉,使用pcap_get_selectable_fd獲得的實時捕捉文件描述符pcap_fdpcap_fd添加READ_EV事件到libevent的循環。 無論如何,它就像select()或epoll()輪詢文件描述符。

但我注意到按預期程序不能正常工作,所以我使用tcpdump和一些調試日誌,以檢查問題。我注意到有時,pcap_fd上的輪詢無法正常工作,例如,在開始時,它似乎工作正常。一段時間後,pcap_fd的READ_EV事件在2秒後觸發,這實際上是一個很大的延遲。

我讀了mannual,它說:

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()pcap_dispatch輪詢實時捕捉,是不是?那麼我的輪詢可能會非常耗費CPU? !

感謝

回答

1

有問題的段落可能是

注意,在大多數BSD系統(包括Mac OS X)選擇() 和poll()不要BPF設備正常工作的大多數版本; ()會在 版本中返回一個文件描述符(例外的是FreeBSD 4.3和4.4),即使在 pcap_open_live()指定的超時之後,簡單的select() 或poll()也不會返回。要解決這個問題,那 使用選擇一個應用程序()或poll()來等待數據包到達必須把 pcap_t在非阻塞模式,並且必須安排的選擇()或 輪詢()有超時小於或等於 pcap_open_live()中指定的超時時間,並且必須嘗試在超時 過期後讀取數據包,而不管select()或poll()是否指示pcap_t的 文件描述符已準備好讀取或不。 (這與工作 各地的FreeBSD 4.3和更高版本將無法正常工作;但是在FreeBSD的4.6 後來,選擇()和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的一個bug BPF,非阻塞模式無法正常工作,因此該解決方法也不適用於OS X 10.6,在10.7及更高版本中不需要)

如果您使用的是libevent,則應該將pcap_fd進入非阻塞模式,使用pcap_setnonblock()不是fcntl()!),如果您t READ_EV事件,使用pcap_dispatch()來處理數據包。