不用回调函数来捕捉数据包

不用回调函数来捕捉数据包

 

 

     这节课举的例子很象上节课的例子(获得已经安装设备的高级信息),但是这个例子我们用的是函数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_headerpkt_data不会指向一个合法的数据包。

 

       返回-1:发生错误

 

       返回-2:从一次离线捕获中读取数据遇到了EOF 

 

Code

 

00001 #include "pcap.h"

 

 

00002 

 

 

00003 

 

 

00004 main()

 

 

00005 {

 

 

00006 pcap_if_t *alldevs;

 

 

00007 pcap_if_t *d;

 

 

00008 int inum;

 

 

00009 int i=0;

 

 

00010 pcap_t *adhandle;

 

 

00011 int res;

 

 

00012 char errbuf[PCAP_ERRBUF_SIZE];

 

 

00013 struct tm *ltime;

 

 

00014 char timestr[16];

 

 

00015 struct pcap_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()方法,文档里面没有介绍是阻塞得还是非阻塞,个人认为是阻塞得,也就是说从开始执行,一直倒接收倒一个包才返回。尽管这里是阻塞得,但是设置一个变量每次检查一下,看看是否是用户要求关闭接收,这个操作还是没什么问题。不会出现虽然用户设置了停止阻塞得标志位,但是由于此方法是阻塞的,因为等不到数据包而一直没有响应用户,因为这里有一个事实大家应该明白,网上发送的数据包时时刻刻都在。

 

 

注意:之所以要使用pcap_next_ex()而不使用pcap_next()是因为pcap_next()有些非常讨厌的限制。首先,他不是很有效的方法,因为它隐藏了回调方法,但是还是依靠pcap_dispatch()。第二,它不能探测出EOF,所以在合并文件时它几乎没用。

 

     另外,pcap_next_ex()方法的返回值可以给用户很多的提示,对应的所有可能情况。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值