WinPcap基础知识(第一课:获得设备列表) 一个基本的WinPcap应用程序所需的第一件事情是获得合适的网络适配器。Libpcap/ Winpcap提供 pcap_findalldevs() 函数完成这个功能:这个函数返回一个相连的pcap_if结构的列表。列表的每一项包含关于适配器的复杂的信息。特别的,name和description域数据包含设备的名称和可读的描述。如下的代码提取设备列表,然后打印到屏幕上。如果没有发现适配器,则显示一个错误。 view plaincopy to clipboardprint? #include <pcap.h> void main() { } 在第一行 #include <pcap.h>的前面加上#define HAVE_REMOTE,或者你在项目属性里面添加“C语言预处理程序定义”一栏里面加上HAVE_REMOTE(注意用‘,’隔开)。加上HAVE_REMOTE,因为在pcap.h头文件里面对此进行判断,如果定义了符号HAVE_REMOTE,pcap.h头文件会自动包含<remote-ext.h>文件,而该文件中申明了函数pcap_findalldevs_ex()以及宏定义PCAP_SRC_IF_STRING。 代码的解释如下(部分): 首先,象其他libpcap函数一样, pcap_findalldevs()具有一个errbuf参数。该参数指向一个由libpcap填充的字符串。当有错误发生时,错误的描述被写入到这个字符串。 gcc -o testaprog testprog.c -lpcap 在Windows下,你需要建立一个project。按照"Using WinPcap in your programs " 的介绍。不过,我建议你使用WinPcap 开发包(在http://winpcap. 提供下载)。开发包提供很多正确设置的示例程序,并且包含本指南所有代码和编译示例所需的项目、包含文件和库。 编译完成,在我的WinXP工作站上运行程序,结果是 1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter) 2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI) 现在你可以看到,Windows下网络适配器的名称(当打开设备时会传递给libpcap)基本上不知所云,也就是说可读性不好,所以旁边的描述对读者将十分有用。 本课用到的数据结构简介: ①pcap_if 结构: ⑴typedef struct pcap_if pcap_if_t ⑵pcap_if结构里面的数据域: ②pcap_addr结构:代表一个接口地址,在<pcap.h>中定义 数据域: pcap_addr * next if not NULL, a pointer to the next element in the list; NULL for the last element of the list sockaddr * addr a pointer to a struct sockaddr containing an address sockaddr * netmask if not NULL, a pointer to a struct sockaddr that contains the netmask corresponding to the address pointed to by addr. sockaddr * broadaddr if not NULL, a pointer to a struct sockaddr that contains the broadcast address corre- sponding to the address pointed to by addr; may be null if the interface doesn't support broadcasts sockaddr * dstaddr if not NULL, a pointer to a struct sockaddr that contains the destination address corre- sponding to the address pointed to by addr; may be null if the interface isn't a point- to-point interface ⑶函数说明 int pcap_findalldevs_ex pcap_findalldevs_ex函数获得网络设备的一个列表,并且这个列表可以被pcap_open()打开。 Pcap_createsrcstr()进行格式化,然后把source 标识符传递给pcap_open()。 参数说明: Source :该变量告诉函数在哪儿去查找,它和pcap_open()使用通用的语法。它是一个字符串,用来存放源位置(source location),例如:source 可以是”rpcap://”,表示本地适配器;也可以是”rpcap://host:port”,表示远程主机上面的适配器;还可以是pcap文件,例如:source可以是”rpcap://c:/myfolder/”。 auth:指向pcap_rmtauth结构的指针,用来保存连接到远程主机上授权信息。在查询本地机器时,此参数没什么意义,可以为NULL。 alldevs: 指向pcap_if_t结构的指针,该指针不需要初始化,它会在函数的调用过程中进行初始化。此函数返回时,该指针被设置为所获得的设备接口列表的第一个元素,列表的每一个元素都是 Pcap_if_t结构。 errbuf :指向用户分配的缓冲区(大小为PCAP_ERRBUF_SIZE),该buf用来存放出错信息。 返回值: 成功返回0,alldevs返回设备列表,alldevs不会为NULL。否则返回-1,那就是说系统没有任何接口可以列举的。 出错的消息在errbuf里面返回,错误可能由下面的原因造成的: ① ② ③ ④ 注意的问题: Source参数的语法: ⑴两个宏定义: (2)详细描述 下面列举出了能够被pcap_open()函数打开的格式: file://path_and_filename [打开一个本地文件] rpcap://devicename [打开本地机器上面的可以打开的设备,不使用rpcap协议] rpcap://host/devicename [打开远程机子上可以打开的设备] rpcap://host:port/devicename [打开远程机器上面选择的设备,用一个非标准端口作为rpcap] adaptername [打开一个本地适配器,kept for compability,不推荐] (NULL) [打开第一个本地适配器,kept for compability,不推荐] Pcap_findalldevs_ex()允许的格式如下: file://folder/ [列出指定目录的所有文件] rpcap:// [列出本地的适配器] rpcap://host:port/ [列出远程机器上的可以列出的设备] 关于host和port参数,可以为数字或者字母。由于支持IPV6,它们可以是下面的格式: · ?host (numeric IPv4): e.g. 10.11.12.13 ?host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] ?host (numeric IPv6): e.g. [1:2:3::4] 这里是一些例子: rpcap://host.foo.bar/devicename [everything literal, no port number] ?rpcap://host.foo.bar:1234/devicename [everything literal, with port number] ?rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] ?rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] ?rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] ?rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] ?rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] 转自:http://wotseb./1418997.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/19/4457794.aspx WinPcap基础知识(第二课:获得已安装设备的高级信息) 第一课 (Obtaining the device list ) 展示了如何获得有用适配器的基本信息(如设备名称和描述)。事实上,WinPcap也提供另外的高级信息。特别的,每个pcap_findalldevs() 返回的 pcap_if 结构也包含了一个pcap_addr结构的列表: ?该接口的地址列表a list of addresses for that interface. ?网络掩码的列表a list of netmasks (each of which corresponds to an entry in the addresses list). 如下的例子提供一个ifpriont()函数,来打印pcap_if结构的完整内容。它被pcap_findalldevs()返回的每个条目调用。 view plaincopy to clipboardprint? #include <pcap.h> #ifndef WIN32 #else #endif #pragma comment(lib,"ws2_32.lib") // Function prototypes void ifprint(pcap_if_t *d); char *iptos(u_long in); char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen); int main() { } void ifprint(pcap_if_t *d) { } #define IPTOSBUFFERS char *iptos(u_long in) { } char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen) { } 此程序的缺点很明显:显示本机没有问题,但是显示远程主机就一般都不行,它要求双方都要装winpcap包并且对方在后台要运行rpcap,并且接收参数NULL授权参数。笔者试了一下,几乎不能获得远程主机的接口列表。 转自:http://wotseb./1419033.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4458008.aspx WinPcap基础知识(第三课:打开一个适配器捕捉数据包) 现在我们已经知道了怎样去获取一个适配器并使用它,让我们开始真正的工作-----开始抓取网络数据包吧。在这一课中我们将写一个程序,这个程序将在我们选择的适配器上监听,并抓取通过这个适配器上的每一个数据包,打印其中的一些信息。 view plaincopy to clipboardprint? #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap.lib") void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; } void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { } 程序运行说明:程序会打印出在上面时候接收到多大的数据包,注意到pcap_open()函数里面的3个重要参数:snaplen设置为65536保证每次都把整个包抓获;flags设置为混杂模式以便抓获所有的数据包。关于第三个参数to_ms,我运行的环境是WindowsXP,设置这个值对程序指向结果没有影响。 疑问:会不会是to_ms参数不被Wins平台支持? 一旦打开了适配器,就由pcap_dispatch() 或者pcap_loop()开始抓取。这两个函数都非常慢,所不同的是pcap_ dispatch()一旦超时就可以返回(尽管不能保证)而pcap_loop() 会一直等到cnt包被抓到才会返回,所以这个函数在没有数据包的网络中会阻塞任意的时间。在这个例子中pcap_loop()就足够了,而pcap_dispatch() 则可以在一个更复杂的程序中使用。 转自:http://wotseb./1419050.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4458204.aspx WinPcap基础知识(第四课:不用回调函数来捕捉数据包) 这节课程中的例子程序完成的功能和上节课的一样,但是使用的是pcap_next_ex()而不是pcap_loop(). view plaincopy to clipboardprint? #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap.lib") main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; int res; char errbuf[PCAP_ERRBUF_SIZE]; struct tm *ltime; char timestr[16]; struct pcap_pkthdr *header; u_char *pkt_data; } 疑问:没有完全体现出好控制的特征 感觉也只是点点,可以设置一个变量,来控制是否接收下一个数据包,这点还是可以做到得,不过这里是因为数据包太多了,一般不会出现问题。 关于pcap_next_ex()方法,文档里面没有介绍是阻塞得还是非阻塞,个人认为是阻塞得,也就是说从开始执行,一直倒接收倒一个包才返回。尽管这里是阻塞得,但是设置一个变量每次检查一下,看看是否是用户要求关闭接收,这个操作还是没什么问题。不会出现虽然用户设置了停止阻塞得标志位,但是由于此方法是阻塞的,因为等不到数据包而一直没有响应用户,因为这里有一个事实大家应该明白,网上发送的数据包时时刻刻都在。 注意:之所以要使用pcap_next_ex()而不使用pcap_next()是因为pcap_next()有些非常讨厌的限制。首先,他不是很有效的方法,因为它隐藏了回调方法,但是还是依靠pcap_dispatch()。第二,它不能探测出EOF,所以在合并文件时它几乎没用。 转自:http://wotseb./1419069.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4458383.aspx WinPcap基础知识(第五课:过滤信息) WinPcap提供的最强大的特性之一就是过滤引擎。它是被集成到了winpcap的捕获机制中的,提供了一种非常高效的方法来获取部分网络数据。被用来过滤数据包的函数是 pcap_compile() 和 pcap_setfilter()。 view plaincopy to clipboardprint? if (d->addresses != NULL) 如果你想看一些在这节课中讲述的使用过滤功能的代码,请看下节课中的例子,Interpreting the packets. 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4458607.aspx WinPcap基础知识(第六课:翻译数据包) 现在我们已经能够捕获并且过滤网络数据包,下面我们就把我们的知识运用到一个简单的“真实的”应用程序中去。 view plaincopy to clipboardprint? #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap.lib") #pragma comment(lib,"Ws2_32.lib") typedef struct ip_address{ }ip_address; typedef struct ip_header{ }ip_header; typedef struct udp_header{ }udp_header; void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; u_int netmask; char packet_filter[] = "ip and udp"; struct bpf_program fcode; } void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { } 首先,我们设置过滤器为”ip and udp”。这样,我们保证packet_handler()将只接收基于IPv4的udp数据包;这样可以简单化分解(parsing)过程和提高程序的执行效率。 1. Enter the interface number (1-2):1 listening on Xircom CardBus Ethernet 10/100 Adapter... 16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53 16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682 16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53 每一行代表一个数据包。 转自:http://wotseb./1419081.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4458618.aspx WinPcap基础知识(第七课:处理离线dump文件)
view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. { 11. pcap_if_t *alldevs; 12. pcap_if_t *d; 13. int inum; 14. int i=0; 15. pcap_t *adhandle; 16. char errbuf[PCAP_ERRBUF_SIZE]; 17. pcap_dumper_t *dumpfile; 18. 19. 20. 21. 22. if(argc != 2) 23. { 24. printf("usage: %s filename", argv[0]); 25. return -1; 26. } 27. 28. 29. if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 30. { 31. fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 32. exit(1); 33. } 34. 35. 36. for(d=alldevs; d; d=d->next) 37. { 38. printf("%d. %s", ++i, d->name); 39. if (d->description) 40. printf(" (%s)\n", d->description); 41. else 42. printf(" (No description available)\n"); 43. } 44. 45. if(i==0) 46. { 47. printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 48. return -1; 49. } 50. 51. printf("Enter the interface number (1-%d):",i); 52. scanf("%d", &inum); 53. 54. if(inum < 1 || inum > i) 55. { 56. printf("\nInterface number out of range.\n"); 57. 58. pcap_freealldevs(alldevs); 59. return -1; 60. } 61. 62. 63. for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 64. 65. 66. 67. if ( (adhandle= pcap_open(d->name, // name of the device 68. 65536, // portion of the packet to capture 69. // 65536 guarantees that the whole packet will be captured on all the link layers 70. PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 71. 1000, // read timeout 72. NULL, // authentication on the remote machine 73. errbuf // error buffer 74. ) ) == NULL) 75. { 76. fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 77. 78. pcap_freealldevs(alldevs); 79. return -1; 80. } 81. 82. 83. dumpfile = pcap_dump_open(adhandle, argv[1]); 84. 85. if(dumpfile==NULL) 86. { 87. fprintf(stderr,"\nError opening output file\n"); 88. return -1; 89. } 90. 91. printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description); 92. 93. 94. pcap_freealldevs(alldevs); 95. 96. 97. pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile); 98. 99. return 0; 100. 101. 102. 103. 104. 105. 106. 107. 可以看出:这个程序的结构和前面我们学过的课程里面的结构非常相似,不同在于: ⑴接口一打开,就马上调用pcap_dump_open()打开一个dump文件并且把它联系到此接口⑵在packet_handler()回调函数执行中,数据包被pcap_dump()写入到文件中。参数dumpfile被pcap_handler()函数接收,所以保存一个数据包是非常简单的事情。大家要控制好时间,因为网络数据包太多了,时间久了dump的文件就会特别大,到时候你直接打开都要等一会儿....... 从dump文件中读取数据包 既然现在我们有一个dump文件,我们就来看看怎么读取它的内容。下面的代码向我们展示了怎么样打开一个winpcap/libpcap dump文件,然后显示它里面的每一个数据包。这个文件是用pcap_open_offline()打开的,然后在数据包中循环使用pcap_loop()。你可以看到,其实从一个离线的捕获中读取数据包和从一个物理接口上接收他们几乎一样。 下面的例子也介绍了另外一个函数:pcap_createsrcsrc()。这个函数用来创建一个源字符串,这个字符串的开始部分是用来告诉WinPcap要使用的类型,例如:如果我们要打开一个适配器就用”rpcap://”;如果我们要打开一个文件就用file://。在你使用pcap_findalldevs_ex()时这个步骤不是必须的(因为返回值已经包含了这些字符串)。但是,在此例中必需,因为我们要从用户的输入中读取到文件的名字。 转自:http://wotseb./1419199.html WinPcap基础知识(第八课:发送数据包) 尽管WinPcap这个名字已经很清晰的表明这个库是用来捕获数据包的,但是另外一个非常有用的功能是提供了原始网络操作。这里,用户可以找到一系列函数来发送数据包,这节课我们就会向大家一一展示。注意到原始的libcap库不提供任何方法来发送数据库:这里讲的所有的函数是WinPcap扩展,它们不能在Unix系统下面工作。用pcap_sendpacket()发送单个数据包函数原型: int pcap_sendpacket ( pcap_t * p, u_char * buf, int size ) 说明:该函数可以发送一个原始数据包到网络上。Buf包含要发送到网络上的数据包的数据(包括协议头)。注意,MAC CRC不用包含,因为它是网卡驱动计算然后添加的。返回值为0说明数据包已经成功的发送了,否则返回-1。 用pcap_sendpacket()发送单个包 最简单发送一个数据包的方法如下面代码所示。打开一个适配器后,调用pcap_sendpacket()来发送一个手工数据包。Pcap_sendpacket()的参数如下:一个包含将要发送的数据缓冲区;缓冲区的长度;将要在它上面发送数据的适配器。注意到缓冲区的数据是不经过处理就被发送到网络上的,这就意味着应用程序必须要创建正确的协议头以保证发送一些有用的信息。 view plaincopy to clipboardprint? 01.#include <stdlib.h> 02.#include <stdio.h> 03. 04.#define HAVE_REMOTE 05.#include <pcap.h> 06. 07.#pragma comment(lib,"wpcap") 08. 09. 10.void main(int argc, char **argv) 11.{ 12.pcap_t *fp; 13.char errbuf[PCAP_ERRBUF_SIZE]; 14.u_char packet[100]; 15.int i; 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67.} 发送队列 Pcap_sendpacket()提供了一个简单而又直接的方法来发送一个数据包,发送队列提供了一个高级的有效的最优化机制来发送一组数据包。一个发送队列是一个用来存放即将要发送到网络上的多个数据包的容器。它有大小,大小表明了它能够存放的数据包的最大数量。发送队列是通过调用pcap_sendqueue_alloc()函数来创建的,创建时要指定所需创建的队列的大小。一旦队列创建完毕,就可以使用pcap_sendqueue_queue()来存放一个数据包在队列里面。此函数获得一个带有时间戳,长度,数据包缓冲区的pcap_pkthdr。这些参数同样被pcap_next_ex()和函数pcap_handler()接收。因此,把一个刚捕获的或者从文件中读取出来的数据包放到队列中去就是把数据包作为参数传递给pcap_sendqueue_queue()。 看看几个函数 int pcap_sendqueue_queue 功能:向发送队列中添加一个数据包。Pcap_sendqueue_queue()方法向队列得末尾添加一个数据包。Pkt_header参数指向一个pcap_pkthdr结构体(结构体含有数据包得时间戳,长度,以及一个pkt_data指针,它指向包数据的指针)。Pcap_ptkhdr结构在Winpcap和libcap里面都是用来存放包,因此发送一个捕获文件时直接发送的。“原始包”意味着发送应用程序将必须包含协议头。 CRC头就不用了,那是网卡驱动程序进行计算然后加上的。 u_int pcap_sendqueue_transmit 功能:把一个装有原始包的队列发送到网络上。注意一下参数sync,它决定发送操作是否必须同步。如果是非0,数据包发送要注意时间戳(the packets are sent respecting the timestamps);否则,数据包尽可能快的发送出去。 为了发送一个队列,WinPcap提供了pcap_sendqueue_transmit()函数。注意一下第三个参数:如果是非空,发送就是同步的。例如:数据包的相关的时间戳也会被重视。这就需要占用大量cpu资源,因为同步方式代替在内核。。。。。(翻译不出来) 当不再需要一个队列,就可以用pcap_sendqueue_destroy()函数来释放,它会释放与之关联的所有的缓冲区。 下面的代码显示了怎么样使用发送队列。首先它用pcap_open_offline()函数打开一个捕获文件,然后把数据包从文件中拷贝到合适分配的队列里面。这时,开始传送队列。 注意到dump文件的链路层是与使用pcap_datalink()方法来发送数据包所在的其中一个接口一致的。如果他们不同的话就会打印出一个警告:sending on a link-layer the packets captured from a different one is quite pointless. view plaincopy to clipboardprint? #include <stdlib.h> #include <stdio.h> #define WPCAP #define HAVE_REMOTE #include <pcap.h> #pragma comment(lib,"wpcap") void usage(); void main(int argc, char **argv) { } void usage() { } 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4459058.aspx WinPcap基础知识(第九课:统计网络的通信量) 这节课我们将要学习WinPcap的另外一个高级特性:对网络通信量进行统计。统计引擎使得内核级的包过滤器能有效的把收集到的包分类。你可以查阅NPF 驱动内部手册看到更多的细节。 为了用这个功能来监视网络,程序员必须要打开一个适配器,并且把它设为统计模式。可以用函数pcap_setmode()来完成这个功能。特别的,在这个函数里面MODE_STAT必须作为模式参数。 用统计模式,我们写一个监视TCP通信负载的应用程序,只需要很少行代码。下面是例子代码: view plaincopy to clipboardprint? #include <stdlib.h> #include <stdio.h> #include <pcap.h> void usage(); void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *); void main(int argc, char **argv) { pcap_t *fp; char errbuf[PCAP_ERRBUF_SIZE]; struct timeval st_ts; u_int netmask; struct bpf_program fcode; } void dispatcher_handler(u_char *state, const struct pcap_pkthdr *header, const u_char *pkt_data) { } void usage() { } Before enabling statistical mode, the user has the option to set a filter that defines the subset of network traffic that will be monitored. See the paragraph on the Filtering expression syntax for details. If no filter has been set, all of the traffic will be monitored. Once ?pcap_setmode() is called ?callback invocation is enabled with pcap_loop() the interface descriptor starts to work in statistical mode. Notice the fourth parameter (to_ms) of pcap_open(): it defines the interval among the statistical samples. The callback function receives the samples calculated by the driver every to_ms milliseconds. These samples are encapsulated in the second and third parameters of the callback function, as shown in the following figure: Two 64-bit counters are provided: the number of packets and the amount of bytes received during the last interval. In the example, the adapter is opened with a timeout of 1000 ms. This means that dispatcher_handler() is called once per second. At this point a filter that keeps only tcp packets is compiled and set. Then pcap_setmode() and pcap_loop() are called. Note that a struct timeval pointer is passed to pcap_loop() as the user parameter. This structure will be used to store a timestamp in order to calculate the interval between two samples. dispatcher_handler()uses this interval to obtain the bits per second and the packets per second and then prints these values on the screen. Note finally that this example is by far more efficient than a program that captures the packets in the traditional way and calculates statistics at user-level. Statistical mode requires the minumum amount of data copies and context switches and therefore the CPU is optimized. Moreover, a very small amount of memory is required. 摘自:http://www./docs/docs_41b5/html/group__wpcap__tut9.html 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/08/18/4459314.aspx |
|