2012-07-24 58 views
6

我有一个程序向主机发送一组TCP SYN数据包(使用原始套接字),并使用libpcap(带过滤器)来获取响应。我试图在一个异步I/O框架中实现它,但libpcap似乎缺少一些响应(即在TCP SYN和响应之间的时间小于100 microseconds时系列中的第一个数据包)。该PCAP手柄的设置是这样的:异步libpcap:丢失数据包?

pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer); 
pcap_setnonblock(pcap, true, errorBuffer); 

然后我添加过滤器(包含在filterExpression字符串):

struct bpf_program filter; 
pcap_compile(pcap, &filter, filterExpression.c_str(), false, 0); 
pcap_setfilter(pcap, &filter); 
pcap_freecode(&filter); 

而且在环路上,发送每个数据包之后,我使用select知道如果我可以从libpcap的阅读:

int pcapFd = pcap_get_selectable_fd(pcap); 
fd_set fdRead; 
FD_ZERO(&fdRead); 
FD_SET(pcapFd, &fdRead); 
select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout); 

并阅读:

if (FD_ISSET(pcapFd, &fdRead)) { 
    struct pcap_pkthdr* pktHeader; 
    const u_char* pktData; 
    if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) { 
     // Process received response. 
    } 
    else { 
     // Nothing to receive (or error). 
    } 
} 

正如我之前所说的,一些数据包错过了(落入“无法接收”其他)。我知道这些数据包在那里,因为我可以用同步方式捕获它们(使用tcpdump或运行pcap_loop的线程)。我在这里错过了一些细节吗?或者这是libpcap的问题?

+0

可能出现这种情况,您发送太多请求的速度太快,并且服务器发送的响应速度更快,您可以处理它们,从而过载OS的网络缓冲区并丢弃数据包。或者有可能你的receiver socket没有及时处理最初的响应。你能否证实你假设你收到的所有回应实际上都到达了那里? Todo会同时在与应用程序相同的接口上运行tcpdump。如果你在tcpdump中看到所有的数据包,而不是在应用程序中,你可能会遇到上述问题之一。 – ryanbwork 2012-07-24 19:10:14

+0

我已经做到了(tcpdump在一边,但也是pcap_loop一个不同的线程),并且所有的数据包都在那里。因此,我不相信我发送的回复太快了。我怎么知道我的接收器插座(即libpcap)还没有安装?这是有道理的,因为失落的回应总是第一或第二。 – 2012-07-24 19:16:07

+0

即使您看到tcpdump中的数据包,如果您的应用程序无法处理它们收到的速率,它们仍可能被操作系统丢弃。如果您的应用程序在发送响应之后启动,请尝试在从服务器发送初始响应之前添加一些重要延迟;如果您成功收到所有回复,就会发现您的问题。 – ryanbwork 2012-07-24 19:22:58

回答

1

这似乎是在Linux下使用内存映射的libpcap的问题。详情请参阅my other question

+0

那么,你有没有解决这个问题?如何启用libpcap的内存映射? – misteryes 2013-05-14 09:48:34

1

如果为pcap_t的FD被select()报告为可读(或poll()或任何呼叫您正在使用/机构),也不能保证,这意味着只有一个数据包可以无阻塞地读。

如果使用pcap_next_ex(),则只能读取一个数据包;如果有多个数据包可以读取,那么,如果你做了另一个select(),它应该立即返回,报告FD再次可读,在这种情况下,你可能会再次呼叫pcap_next_ex(),依此类推。这意味着每个数据包至少有一个系统调用(select()),可能还有更多的调用,具体取决于您正在执行的操作系统版本以及您拥有的libpcap版本。

如果您调用pcap_dispatch(),并且数据包计数参数为-1,则该调用将返回所有可通过单个读取操作获取的数据包并处理所有这些数据包,因此,大多数平台,如果有多个数据包可用(如果网络流量较高,如果使用SYN泛洪测试程序,则可能会得到多个数据包),那么您可能会收到多个带有一个或两个系统调用的数据包,情况可能如此) 。另外,在支持内存映射数据包捕获的Linux系统上(我认为所有的2.6和更高版本的内核都可以,大多数如果不是所有的2.4内核都这样做的话),并且在更新版本的libpcap中,pcap_next_ex()必须复制以避免内核在处理数据包的代码下改变数据包,并避免在一个无限期的时间内“锁定”环形缓冲区中的一个插槽,因此需要额外的复制。

+0

+1对于不熟悉异步I/O的用户来说一个常见的陷阱:)你应该保持readin!))) – 2012-07-25 00:58:52

+0

尽管这是有用的信息,但在这里并不是这样。主要的问题是'select'指责一个活动的'pcap_t',然后'pcap_next_ex'返回零。请注意,“丢失的数据包”正在落入“无法接收”的范围。 – 2012-07-25 04:45:42