主要是学习pcap_next_ex()函数如何代替pcap_loop()函数。
pcap_loop()函数是基于回调的原理来进行数据捕获,这是一种精妙的方法,并且在某些场合中,这是一种很好的选择。然而,处理回调有时候并不实用--它会增加程序的复杂度,特别是在拥有多线程的c++程序中。
可以通过直接调用pcap_next_ex()函数来捕获一个数据包--只在当编程人员使用了pcap_next_ex()函数才能收到数据包。
#include<iostream>
#include<pcap.h>
int main()
{
pcap_if_t *alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
//获取本机设备列表
if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1)
{
std::cerr<<"Error in pcap_findalldevs:"<<errbuf<<std::endl;
exit(1);
}
//打印列表
int i=0;
pcap_if_t *d;
for(d=alldevs;d;d=d->next)
{
std::cout<<++i<<"."<<d->name<<std::endl;
if(d->description)
std::cout<<d->description<<std::endl;
else
std::cout<<"(No description available)"<<std::endl;
}
if(i==0)
{
std::cout<<"\nNo interface found!Make sure WinPcap is installed."<<std::endl;
return -1;
}
std::cout<<"Enter the interface number(1-"<<i<<")";
int inum;
std::cin>>inum;
if(inum<1||inum>i)
{
std::cout<<"\nInterface number out of range."<<std::endl;
pcap_freealldevs(alldevs);
return -1;
}
//跳转到选中的适配器
for(d=alldevs,i=0;i<inum-1;d=d->next,++i);
//打开设备
pcap_t *adhandle;
if((adhandle=pcap_open(d->name, //设备名
65536,
PCAP_OPENFLAG_PROMISCUOUS, //混杂模式
1000, //读取超时时间
NULL, //远程机器验证
errbuf //错误缓冲池
))==NULL)
{
std::cerr<<"\nUnable to open the adapter."<<d->name<<" is not supported by WinPcap"<<std::endl;
pcap_freealldevs(alldevs);
return -1;
}
std::cout<<"\nlistening on "<<d->description<<"..."<<std::endl;
pcap_freealldevs(alldevs);
//开始捕获
int res;
tm *ltime;
char timestr[16];
pcap_pkthdr *header;
const u_char *pkt_data;
time_t local_tv_sec;
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,%.d 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 0;
}
值得注意的是,pcap_next_ex()在成功、超时、出错或EOF的情况下,会返回不同的值。
最后欢迎大家访问我的个人网站: 1024s