1.7.3 发送队列方式的接口实现
1.7.3.1 PacketSendPackets函数
函数发送数据包队列到网络,函数原型如下:
INT PacketSendPackets(LPADAPTER AdapterObject,
PVOID PacketBuff, ULONG Size, BOOLEAN Sync)
参数AdapterObject指向一个_ADAPTER结构体,该结构体表示将发送数据包的网络适配器。
参数PacketBuff指向待发送数据包的缓冲区。
参数Size为参数PacketBuff所指缓冲区的大小。
参数Sync如果为TRUE,则根据时间戳发送数据包。如果为FALSE,则不根据时间戳,而是尽所能的快速发送各数据包。
函数返回值为实际所发送的字节数,如果该值小于Size参数规定的大小,那么发送过程中出现了错误。错误可能由驱动程序/适配器的问题或冲突的/假的数据包缓冲区导致。
该函数用来发送一个原始数据包缓冲区的内容到网络。该缓冲区能够包含任意数目的原始数据包,每个数据包都有一个dump_bpf_hdr结构体作为数据包的前缀。WinPcap或libpcap在文件中存储数据包使用一样的dump_bpf_hdr结构体,因此可以很直接的发送一个捕获的数据包文件。'Raw packets'意味着发送应用程序将不得不包含协议头,既然每个数据包’照原来的样子’被发送到网络。但是数据包的CRC并不需要计算,明显地,它将被网络接口添加。
注意:使用该函数 比直接使用一连串PacketSendPacket函数更有效率,因为数据包被缓冲到内核驱动,因此上下文的切换明显降低了。
注意:当Sync设置为TRUE,那么内核中的数据包将与一个高精度时间戳同步发送。这个操作需要消耗大量的CPU资源,但数据包的发送通常很精确(可达数微秒左右),这依赖于机器的性能计数器(performance counter)的精度。如此精度是采用pcap_sendpacket函数不可能达到的。
INT PacketSendPackets(LPADAPTER AdapterObject,
PVOID PacketBuff, ULONG Size, BOOLEAN Sync)
{
BOOLEAN Res;
DWORD BytesTransfered, TotBytesTransfered=0;
struct timeval BufStartTime;
LARGE_INTEGER StartTicks, CurTicks, TargetTicks, TimeFreq;
if (AdapterObject->Flags == INFO_FLAG_NDIS_ADAPTER)
{
/*获得发送队列的起始时间戳*/
BufStartTime.tv_sec =
((struct timeval*)(PacketBuff))->tv_sec;
BufStartTime.tv_usec =
((struct timeval*)(PacketBuff))->tv_usec;
/*获的参考的时间计数器*/
QueryPerformanceCounter(&StartTicks);
QueryPerformanceFrequency(&TimeFreq);
CurTicks.QuadPart = StartTicks.QuadPart;
do{
//把数据发送给驱动程序
Res = (BOOLEAN)DeviceIoControl(
AdapterObject->hFile,
(Sync)?BIOCSENDPACKETSSYNC:BIOCSENDPACKETSNOSYNC,
(PCHAR)PacketBuff + TotBytesTransfered,
Size - TotBytesTransfered,
NULL,
0,
&BytesTransfered,
NULL);
TotBytesTransfered += BytesTransfered;
//从循环中退出,发送结束或出错
if(TotBytesTransfered >= Size || Res != TRUE)
break;
//计算发送下一块数据的时间间隔
TargetTicks.QuadPart =
StartTicks.QuadPart +
(LONGLONG)((((struct timeval*)
((PCHAR)PacketBuff + TotBytesTransfered))->tv_sec –
BufStartTime.tv_sec) * 1000000
+
(((struct timeval*)
((PCHAR)PacketBuff + TotBytesTransfered))->tv_usec
- BufStartTime.tv_usec)) *(TimeFreq.QuadPart
) / 1000000;
//等待时间间隔的逝去
while( CurTicks.QuadPart <= TargetTicks.QuadPart )
QueryPerformanceCounter(&CurTicks);
}
while(TRUE);
}
else
{//错误,未知设备类型
TotBytesTransfered = 0;
}
return TotBytesTransfered;
}
本文出自 “千江月” 博客,请务必保留此出处http://eslxf.blog.51cto.com/918801/214880
转载于:https://blog.51cto.com/runhook/387939