libpcap-第四课:不用回调函数来捕捉数据包 - 我的文章 - 汪汪学D

来源:百度文库 编辑:神马文学网 时间:2024/04/25 14:13:49


libpcap-第四课:不用回调函数来捕捉数据包
第四课:不用回调函数来捕捉数据包
这节课举的例子很象上节课的例子(获得已经安装设备的高级信息),但是这个例子我们用的是函数pcap_next_ex()而不是用pcap_loop()。
在某些情况下面,基于回调函数来捕获数据包的pcap_loop()方面是很好的选择,但是,处理一个回调函数有时候是不现实的。通常它会使得程序变得非常复杂并且在多线程应用程序或者在C++类里面它会成为一块心病。
pcap_next_ex()方法可以让我们直接调用来获得数据包。使用pcap_next_ex()可以获得程序的完全控制,因为仅仅在程序要捕获数据包的时候数据包才会接收。
在下面的程序里面,调用完pcap_next_ex(),我们重复使用上次课例子里面的回调函数代码,然后在main函数里面去掉他们。
函数  int pcap_next_ex  (  pcap_t *  p,
struct pcap_pkthdr **  pkt_header,
const u_char **  pkt_data  )
作用:从一个接口上面读取数据包或者从一个离线捕捉中读取数据包。该函数经常用来获取下一个可用的数据包,而避免使用LibPcap提供的传统的使用回调函数的方法。
参数:
pcap_t * 在头文件里面有定义:pcap_t就是pcap的别名。
参数前面都已经出现过,这里就不做详细介绍了。
返回值:
返回1:如果读取数据包没有出现错误。
返回0:如果pcap_open_live()设置的timeout时间到了。此时,ptk_header和pkt_data不会指向一个合法的数据包。
返回-1:发生错误
返回-2:从一次离线捕获中读取数据遇到了EOF。
【Code】
00001 #include "pcap.h"
00002
00003
00004main()
00005 {
00006pcap_if_t *alldevs;
00007pcap_if_t *d;
00008 int inum;
00009 int i=0;
00010pcap_t *adhandle;
00011 int res;
00012 char errbuf[PCAP_ERRBUF_SIZE];
00013 struct tm *ltime;
00014 char timestr[16];
00015 structpcap_pkthdr *header;
00016 u_char *pkt_data;
00017
00018
00019     /* Retrieve the device list on the local machine */
00020     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
00021     {
00022         fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
00023         exit(1);
00024     }
00025
00026     /* Print the list */
00027     for(d=alldevs; d; d=d->next)
00028     {
00029         printf("%d. %s", ++i, d->name);
00030         if (d->description)
00031             printf(" (%s)\n", d->description);
00032         else
00033             printf(" (No description available)\n");
00034     }
00035
00036     if(i==0)
00037     {
00038         printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
00039         return -1;
00040     }
00041
00042     printf("Enter the interface number (1-%d):",i);
00043     scanf("%d", &inum);
00044
00045     if(inum < 1 || inum > i)
00046     {
00047         printf("\nInterface number out of range.\n");
00048         /* Free the device list */
00049        pcap_freealldevs(alldevs);
00050         return -1;
00051     }
00052
00053     /* Jump to the selected adapter */
00054     for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
00055
00056     /* Open the device */
00057     if ( (adhandle=pcap_open(d->name,          // name of the device
00058                               65536,            // portion of the packet to capture.
00059                                                 // 65536 guarantees that the whole packet will be captured on all the link layers
00060                               PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
00061                               1000,             // read timeout
00062                               NULL,             // authentication on the remote machine
00063                               errbuf            // error buffer
00064                               ) ) == NULL)
00065     {
00066         fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
00067         /* Free the device list */
00068        pcap_freealldevs(alldevs);
00069         return -1;
00070     }
00071
00072     printf("\nlistening on %s...\n", d->description);
00073
00074     /* At this point, we don't need any more the device list. Free it */
00075    pcap_freealldevs(alldevs);
00076
00077     /* Retrieve the packets */
00078     while((res =pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){
00079
00080         if(res == 0)
00081             /* Timeout elapsed */
00082             continue;
00083
00084         /* convert the timestamp to readable format */
00085         ltime=localtime(&header->ts.tv_sec);
00086         strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
00087
00088         printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
00089     }
00090
00091     if(res == -1){
00092         printf("Error reading the packets: %s\n",pcap_geterr(adhandle));
00093         return -1;
00094     }
00095
00096     return 0;
00097 }
程序运行说明:按照前面所说的加上宏定义即可。
疑问:没有完全体现出好控制的特征
感觉也只是点点,可以设置一个变量,来控制是否接收下一个数据包,这点还是可以做到得,不过这里是因为数据包太多了,一般不会出现问题。关于pcap_next_ex()方法,文档里面没有介绍是阻塞得还是非阻塞,个人认为是阻塞得,也就是说从开始执行,一直倒接收倒一个包才返回。尽管这里是阻塞得,但是设置一个变量每次检查一下,看看是否是用户要求关闭接收,这个操作还是没什么问题。不会出现虽然用户设置了停止阻塞得标志位,但是由于此方法是阻塞的,因为等不到数据包而一直没有响应用户,因为这里有一个事实大家应该明白,网上发送的数据包时时刻刻都在。