这一次要分析的实例程序跟上一讲非常类似(“打开适配器并捕获数据包”),略微不同的一点是本次将pcap_loop()函数替换成了pcap_next_ex()函数。本节的重点也就是说一下这两个函数之间的差异。我们知道pcap_loop()函数是基于回调的原理来进行数据捕获的,如技术文档所说,这是一种精妙的方法,并且在某些场合下,它是一种很好的选择。但是在处理回调有时候会并不实用,它会增加程序的复杂度,特别是在多线程的C++程序中。而对于pcap_next_ex()函数而言,可以通过直接调用它来获得一个数据包,也只有在调用了这个函数才能收到数据包。pcap_next_ex()函数跟pcap_loop()的回调函数参数是相同的:
int pcap_next_ex ( pcap_t * p,
struct pcap_pkthdr ** pkt_header,
const u_char ** pkt_data
)
第一个参数是网络适配器的描述符;第二个参数是一个指向pcap_pkthdr结构体的指针;第三个参数是指向数据报数据的缓冲的指针。
来看一下实例程序的代码:
#include "pcap.h" #include <QCoreApplication> #include <winsock2.h> #include <ws2tcpip.h> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); pcap_if_t *alldevs; pcap_if_t *d; int i = 0; int inum; pcap_t *adhandle; int res; char errbuf[PCAP_ERRBUF_SIZE]; struct tm *ltime; char timestr[16]; struct pcap_pkthdr *header; const u_char *pkt_data; time_t local_tv_sec; /* 获取本地机器设备列表 */ if (pcap_findalldevs_ex((char *)PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1) { fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf); exit(1); } /* 打印列表 */ for (d = alldevs; d != NULL; d = d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if (i == 0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):", i); scanf("%d", &inum); if (inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* 释放设备列表 */ pcap_freealldevs(alldevs); return -1; } /* 跳转到选中的适配器 */ for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++) ; /* 打开设备 */ if ((adhandle = pcap_open( d->name, // 设备名 65535, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容 PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式 1000, // 读取超时时间 NULL, // 远程机器验证 errbuf // 错误缓冲池 )) == NULL) { fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /* 释放设备列表 */ pcap_freealldevs(alldevs); return -1; } printf("\nlistening on %s...\n", d->description); /* 不再需要设备列表了,释放它 */ pcap_freealldevs(alldevs); /* 开始捕获 */ while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) { if (res == 0) /* 超时时间到 */ continue; /* 将时间戳转换成可识别的格式 */ local_tv_sec = header->ts.tv_sec; ltime = localtime(&local_tv_sec); strftime(timestr, sizeof timestr, "%H:%M:%S", ltime); printf("%s,%.6ld len:%d\n", timestr, header->ts.tv_usec, header->len); } if (res == -1) { printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); return -1; } return a.exec(); }
文档上在最后简单地比较了一下pcap_next_ex()函数和pcap_next()函数的区别,通过函数名我们知道pcap_next_ex()函数是在pcap_next()基础上扩展得到的。为什么会扩展?根据文档说明可以知道,pcap_next()函数有一些缺陷。比如它效率很低,尽管隐藏了回调的方式,但它仍然依赖于函数pcap_dispatch();另外,它不能检测到EOF这个状态,那么如果数据包是从文件中读取过来的,那么它就不那么好用了。显然,pcap_next_ex()函数在此基础上做出了一些改进。最后我们来看一下pcap_next_ex()函数的返回值,引用文档中的描述:
运行结果:
0.0分
0 人评分
C二级辅导-进制转换 (C语言代码)浏览:661 |
C语言程序设计教程(第三版)课后习题6.3 (C语言代码)浏览:1001 |
C语言程序设计教程(第三版)课后习题7.4 (C语言代码)浏览:1315 |
C语言程序设计教程(第三版)课后习题9.1 (C语言代码)浏览:710 |
简单的a+b (C语言代码)浏览:1025 |
2003年秋浙江省计算机等级考试二级C 编程题(1) (C语言代码)浏览:567 |
字符逆序 (C语言代码)浏览:675 |
震宇大神的杀毒软件 (C语言代码)浏览:1165 |
C语言程序设计教程(第三版)课后习题5.7 (C语言代码)浏览:593 |
拆分位数 (C语言代码)浏览:464 |