您的位置:首页 > 其它

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

2010-06-23 10:39 411 查看
本文转自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,每个数据包之间的时间间隔dus为20微秒,然后调用应用程序的send_queue函数发送数据包。
send_queue(adhandle,100,20);
示例程序代码如下:[send_queue工程]

#define WIN32

#define H***E_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)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: