Ø
应用软件每次发送一个数据包一次;
Ø
应用软件每次发送一个数据包大于一次,次数预先设定;
为了能够发送大量的数据包,
WinPcap
提供了基于发送队列发送的方式。通过发送队列提供了一种高级的,强大的,结构更优的方式来发送一组数据包。
库
wpcap.dll
中与发送队列相关的函数所使用的
pcap_send_queue
结构体,是存储原始数据包
(
将被
pcap_sendqueue_transmit
函数发送到网络上的数据包
)
的数据结构,具体定义如下:
u_int maxlen;
//
队列最大长度
(
字节数
)
,描述了
buffer
成员的容量
char
*buffer;
//
储存待发数据包的缓冲区
typedef
struct
pcap_send_queue pcap_send_queue;
1.6.2.1
pcap_sendqueue_alloc
与
pcap_sendqueue_destroy
函数
发送队列通过调用
pcap_sendqueue_alloc
函数创建,并且需要指定队列的大小。函数的原型如下:
pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
函数分配存储发送数据包队列的内存空间
,发送队列是一个容器,它能容纳不同数量的数据包,这些数据包将被
pcap_sendqueue_transmit
函数发送到网络上。其中参数
memsize
是队列的大小(以字节为单位),决定了发送队列能存储数据包的最大容量。
函数成功返回所分配队列的内存指针,否则返回
NULL
。
pcap_send_queue* pcap_sendqueue_alloc(u_int memsize)
(pcap_send_queue*)malloc(
sizeof
(pcap_send_queue));
/*
分配发送队列
buffer
成员的内存空间
*/
tqueue->buffer = (
char
*)malloc(memsize);
if
(tqueue->buffer == NULL){
tqueue->maxlen = memsize;
//
设置发送队列的最大存储空间
tqueue->len = 0;
//
初始化发送队列的已用存储空间
注意内存空间大小
memsize
参数应该包括每个数据包的头信息
(
struct pcap_pkthdr
)
空间,使用示例如下:
squeue=pcap_sendqueue_alloc(
(unsigned int)((MaxPacketLen+sizeof(struct pcap_pkthdr))*npacks) );
当发送队列不再需要时,需要使用
pcap_sendqueue_destroy
函数来
释放它所占用的内存,该函数原型如下:
void pcap_sendqueue_destroy(pcap_send_queue *queue);
void
pcap_sendqueue_destroy(pcap_send_queue* queue)
free(queue->buffer);
//
释放发送队列
buffer
成员的内存空间
free(queue);
//
释放发送队列结构体的空间
1.6.2.2
pcap_sendqueue_queue
函数
一旦发送队列被创建,就可以通过
pcap_sendqueue_queue
函数将数据包添加到发送队列中,该函数把一个数据包添加到
queue
参数所指的发送队列的尾部。函数原型如下:
int pcap_sendqueue_queue(pcap_send_queue *queue,
const struct pcap_pkthdr *pkt_header,
其中参数
queue
就是调用
pcap_sendqueue_alloc
函数所分配的发送队列,参数
pkt_header
为
WinPcap
为待发数据包所附加的数据头信息,用来说明数据包的长度与发送时间戳,参数
pkt_data
为待发数据包。
函数
pcap_sendqueue_queue
的具体实现如下:
int
pcap_sendqueue_queue(pcap_send_queue* queue,
const
struct
pcap_pkthdr *pkt_header,
if
(queue->len +
sizeof
(
struct
pcap_pkthdr) +
pkt_header->caplen > queue->maxlen)
/*
复制数据包头信息
pcap_pkthdr*/
memcpy(queue->buffer + queue->len, pkt_header,
sizeof
(
struct
pcap_pkthdr));
queue->len +=
sizeof
(
struct
pcap_pkthdr);
memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen);
queue->len += pkt_header->caplen;
1.6.2.3
pcap_sendqueue_transmit
函数
函数
pcap_sendqueue_transmit
用
来发送一个发送队列,该函数原型如下:
u_int pcap_sendqueue_transmit(pcap_t *p,
pcap_send_queue *queue,int sync)
该函数发送一个原始数据包的队列到网络。参数
p
指向一个适配器,数据包将通过该适配器发送,参数
queue
指向一个容纳待发送数据包的
pcap_send_queue
结构体(参见
pcap_sendqueue_alloc
与
pcap_sendqueue_queue
函数),参数
sync
决定了发送操作是否是同步的;如果不为
0
,根据时间戳发送数据包,否则不根据时间戳,而是尽所能的快速发送各数据包。
函数返回值为实际所发送的字节数,如果该值小于希望发送的大小,那么发送过程中出现了错误。错误可能由驱动程序
/
适配器的问题或冲突的
/
假的发送队列导致。
u_int pcap_sendqueue_transmit(pcap_t *p,
pcap_send_queue* queue,
int
sync)
"Cannot transmit a queue to an offline capture
or to a TurboCap port"
);
res =
PacketSendPackets
(p->adapter,
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,
error,0,p->errbuf,PCAP_ERRBUF_SIZE,NULL);
errlen = strlen(p->errbuf);
p->errbuf[errlen - 1] =
'\0'
;
p->errbuf[errlen - 2] =
'\0'
;
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error opening adapter: %s"
, p->errbuf);
请注意,使用
pcap_sendqueue_transmit
函数要比
pcap_sendpacket
函数来发送一系列数据更加有效率,因为发送队列保存在内核层驱动程序的缓冲区中,因此,减少了上下文交换的次数,获得更好的吞吐量。
同时请注意第三个参数
sync
。如果为非零值,那么发送过程将是同步进行,也就是说,只有与时间戳相符的数据包才会被处理。该同步操作由内核驱动程序“忙等待(
busy wait
)”循环来实现,所以这个操作需要消耗大量的
CPU
资源。尽管这个操作对
CPU
的要求很高,但它对数据包发送的处理结通常是很精确的
(
通常在可达数微秒左右,或更小
)
。 如此一个精度是采用
pcap_sendpacket
函数不可能达到的。
本文出自 “
千江月
” 博客,请务必保留此出处
http://eslxf.blog.51cto.com/918801/213826