我正在编写一个C应用程序,它使用pcap库来记录通过网卡传输了多少数据(匹配各种数据包过滤器)。我得到的价值似乎太低而不正确,但我不确定我做错了什么。
下面的测试代码表现出相同的行为(为清楚起见,省略了错误检查):
#include <stdio.h>
#include <pcap.h>
static int total=0;
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){
total += header->len;
printf("%d\n", total);
}
int main(){
char errbuf[1024];
pcap_t *adhandle = pcap_open_live("en1", 65535, 0, 0, errbuf);
pcap_setnonblock(adhandle, 1, errbuf);
struct bpf_program fcode;
pcap_compile(adhandle, &fcode, "port 80", 1, 0);
pcap_setfilter(adhandle, &fcode);
while(1){
pcap_dispatch(adhandle, -1, packet_handler, NULL);
sleep(1);
}
return 0;
}
我正在研究OSX,使用gcc进行编译,我尝试通过wi-fi和有线以太网进行下载。我希望上面的代码打印出与过滤器匹配的字节数(在这种情况下是所有HTTP流量)但是当我下载一个4,357,017字节大小的测试文件时,我得到的值只有95,133。我的测试文件是一个zip存档,所以我不认为HTTP压缩可以解释差异。
更新:我已经修改了代码以打印出每个数据包的大小以及运行总数,并且还仅报告传入的数据包(将过滤器更改为“src”端口80" )。这给出了很多'1514'的数据包长度,我认为这与MTU值1500相关,但总数仍然太低。
答案 0 :(得分:2)
此处无法保证您的程序能够看到所有数据包;如果它没有看到它们,就无法统计它们,在这种情况下,捕获的数据包长度之和小于传输的数据量就不足为奇了。
首先,你不应该使用非阻塞模式,除非你的程序做的不仅仅是捕获数据包 - 轮询在这里不能更好地工作,它可能会更糟。使用您的代码,如果超过缓冲区中的数据包在一秒内到达,系统将耗尽BPF缓冲区空间,这意味着数据包将被丢弃,您的程序将永远不会看到它们,因此不会对它们进行计数。在Lion之前,默认缓冲区大小约为32K左右,这意味着系统很可能会耗尽BPF缓冲区空间; Lion选择了libpcap 1.1更改以使BPF系统的默认缓冲区大小为512K,因此不太可能发生,但除非确实需要它,否则你仍然不应该使用非阻塞模式。< / p>
此外,你不应该在Snow Leopard上使用非阻塞模式 ,因为Snow Leopard中的BPF内核代码存在错误(该错误的FreeBSD版本为{{ 3}});它不存在于Leopard中或之前(它是在修复Snow Leopard中修复的错误中引入的),并且已在Lion中修复。
所以我要做的第一件事就是摆脱pcap_setnonblock(adhandle, 1, errbuf);
调用和sleep(1);
调用,以便你的程序尽可能快地处理数据包。
此外,如果它不必在Leopard上运行(它有一个不支持pcap_create()
或pcap_activate()
的旧版libpcap),我会将缓冲区大小提高到通过执行512K(为清晰起见,删除了错误检查):
adhandle = pcap_create("en1", errbuf);
pcap_set_buffer_size(adhandle, 524288);
pcap_activate(adhandle);
最后,我让你的程序以某种方式提供一种方法来告诉何时停止捕获,当它停止时,让它调用pcap_stats()
并报告丢弃的数据包的数量,以便您可以确定是否它丢弃了任何数据包。