我有一个程序,它将一组TCP SYN数据包发送到主机(使用原始套接字),并使用libpcap(带有过滤器)来获取响应。我正在尝试在异步I/O框架中实现此功能,但是libpcap似乎缺少了一些响应(即,在TCP SYN和响应之间的花费少于100 microseconds时,一系列的第一个数据包)。 pcap句柄的设置如下:

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有问题?

最佳答案

如果pcap_t(或select()或您使用的任何调用/机制)将poll()的FD报告为可读,则无法保证这意味着只能读取一个数据包而不会阻塞。

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

相反,如果要使用packet-count参数-1来调用pcap_dispatch(),那么该调用将返回可以通过一次读取操作获得的所有数据包,并处理所有这些数据包,因此,在大多数平台上,您可能会如果有多个可用数据包,则可以通过一个或两个系统调用来获取多个数据包(网络流量较高,很可能就是这种情况,如果您正在使用SYN Flood测试程序,则可能会得到该数据包)。

此外,在支持内存映射的数据包捕获的Linux系统上(我认为所有2.6及更高版本的内核都支持,大多数(如果不是全部)2.4内核都支持),并且对于较新版本的libpcap,pcap_next_ex()必须将数据包的拷贝复制到避免让内核从处理该数据包的代码下面更改该数据包,并避免无限期“锁定”环形缓冲区中的插槽,因此会涉及额外的拷贝。

关于c++ - 异步libpcap : losing packets?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11637063/

10-10 10:35