深度剖析WinPcap之(九)——数据包的发送过程(2)

来源:互联网 发布:建筑拆除优化设计 编辑:程序博客网 时间:2024/05/24 06:28

本文转自http://eslxf.blog.51cto.com/918801/212406

 

1.3      重复发送单个数据包的示例

我们采用实际代码演示如何重复发送单个数据包。send工程的main.cpp添加下面的代码[send_n工程]
#include <pcap-int.h>
 
/*调用Packet.dll库提供的PacketSetNumWrites函数设置重复发送次数*/
//重复50
PacketSetNumWrites((LPADAPTER)(adhandle->adapter),50);
同时给Linker->Input->Additional Dependencies添加工程依赖的库文件Packet.dll,同时从WinPcap库源代码wpcap/libpcap目录下复制pcap-int.h文件到F:/WpdPack/Include目录下。
运行示例程序,用Wireshark接收示例程序所发送的数据包如图9-3所示。
9-3 Wireshark所接收的数据包

1.4   使用发送队列发送数据包的示例(同步方式)

我们采用实际代码演示如何通过pcap_sendqueue_transmit函数以同步方式发送大量数据包。在main()函数中选择适合的适配器,确定发送数据包的个数为100,每个数据包之间的时间间隔dus20微秒,然后调用应用程序的send_queue函数发送数据包。
send_queue(adhandle,100,20);
示例程序代码如下:[send_queue工程]
#define WIN32
#define HAVE_REMOTE
 
#include <stdio.h>
#include "pcap.h"
#include "Win32-Extensions.h"
 
void send_queue(pcap_t *fp,unsigned int npacks,unsigned int dus);
void genPacket(unsigned char *buf,int len);
timeval add_stamp(timeval *ptv,unsigned int dus);
 
int main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i=0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
   
    /* 获取本机网络设备列表*/
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL,
&alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs:
%s/n", errbuf);
        exit(1);
    }
   
    /* 打印网络设备列表*/
    for(d=alldevs; d; d=d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)/n", d->description);
        else
            printf(" (No description available)/n");
    }
   
    if(i==0)
    {
        printf("/nNo interfaces found!
Make sure WinPcap is installed./n");
        return -1;
    }
 
    /*选择网络设备接口*/
    printf("Enter the interface number (1-%d):",i);
    scanf("%d", &inum);
   
    if(inum < 1 || inum > i)
    {
        printf("/nInterface number out of range./n");
        /* 释放设备列表*/
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    /* 跳转到选中的适配器*/
    for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
   
    /* 打开设备*/
if ( (adhandle= pcap_open(d->name, 65536,                                PCAP_OPENFLAG_PROMISCUOUS, 1000,
NULL, errbuf  ) ) == NULL)
    {
        fprintf(stderr,"/nUnable to open the adapter.
%s is not supported by WinPcap/n", d->name);
        /* 释放设备列表*/
        pcap_freealldevs(alldevs);
        return -1;
    }
 
    /*在选中的设备接口上监听数据*/
    printf("/nlistening on %s.../n", d->description);
       
    /* 开始数据包发送*/
    send_queue(adhandle,100,20);
 
     pcap_close(adhandle);
    pcap_freealldevs(alldevs);
   
    return 0;
}
函数send_queue 负责生成发送队列与发送发送队列,代码具体实现如下:
void send_queue(pcap_t *fp,unsigned int npacks,unsigned int dus)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    int i;        
    unsigned int res;   
   
 
    pcap_send_queue *squeue;        //发送队列  
    const int MaxPacketLen=100;     //数据包长度
 
    struct pcap_pkthdr mpktheader;  //数据包的包头
    struct pcap_pkthdr *pktheader;
    pktheader=&mpktheader;
 
    timeval tv;                   //时间戳
    tv.tv_sec=0;
    tv.tv_usec=0;
 
    //分配发送队列
    squeue=pcap_sendqueue_alloc(
        (unsigned int)(
(MaxPacketLen+sizeof(struct pcap_pkthdr))*npacks)
);
   
    //用数据包填充发送队列
    unsigned char *pBuf=new unsigned char[MaxPacketLen];
    for(i=0;i<npacks;i++)
    {
       memset(pBuf,0x0,MaxPacketLen);
//获得生成的数据包,长度为MaxPacketLen
       genPacket(pBuf,MaxPacketLen);
       //设置数据包的包头
       pktheader->ts=tv;
       pktheader->caplen = MaxPacketLen;
       pktheader->len = MaxPacketLen;
       if (pcap_sendqueue_queue(squeue, pktheader, pBuf) == -1)
        {
            printf("警告数据包缓冲区太小,
不是所有的数据包被发送./n");
            return;
        }
       add_stamp(&tv,dus);  //增加时间戳
       pktheader->ts=tv;    //更新数据包头的时间戳
    }
    delete [] pBuf;
 
    //发送数据包
if ((res = pcap_sendqueue_transmit(fp, squeue, 1))
 < squeue->len)//同步发送
        {
        printf("发送数据包时出现错误:%s. %d字节被发送/n",
           pcap_geterr(fp), res);
       return;
    }  
 
    //释放发送队列
    pcap_sendqueue_destroy(squeue);
 
    return;   
}
 
函数add_stamp增加时间戳,参数ptv修改前后的时间戳结构体指针,参数dus为时间增加的微秒数。函数源代码如下:
timeval add_stamp(timeval *ptv,unsigned int dus)
{
    ptv->tv_usec=ptv->tv_usec+dus; 
    if(ptv->tv_usec>=1000000)
    {
       ptv->tv_sec=ptv->tv_sec+1;
       ptv->tv_usec=ptv->tv_usec-1000000;
    }
    return *ptv;
}
Wireshark接收示例程序所发送的数据包如图9-4所示。
9-4 Wireshark所接收的数据包
Wireshark概要区域的Time字段中可见,接收的时间戳间隔为20微秒,精度差别为2微秒左右,100个数据包总共耗费1966微秒(理论上应该为20*(100-1)=1980微秒);协议Protocol字段显示为0x0c0d
Wireshark详情区域中可看到目标MAC地址为01:01:01:01:01:01,MAC地址为02:02:02:02:02:02
Wireshark数据区域中可看到数据包的内容从0开始递增只到0x55(十进制85)。

原创粉丝点击