WinPcap学习(五)不用回调方法捕获数据包

主要是学习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的情况下,会返回不同的值。

你可能感兴趣的:(WinPcap学习(五)不用回调方法捕获数据包)