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结构体作为数据包的前缀。WinPcaplibpcap在文件中存储数据包使用一样的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