1.7.2 单个数据包发送多次的接口实现
为发送数据包,一个用户层应用程序在NPF设备上执行一个WriteFile系统调用。这样发送每一个数据包都需要一次系统调用,网络数据包的发送效率并不是非常高。因为该原因,WinPcap添加了使用一次写系统调用就能把单个数据包发送多次的功能。用户层应用程序能够设置单个数据包发送的次数,例如设为1000,那么应用程序所写的每个原始数据包在驱动设备文件上都将会发送1000次。应用程序能够用该特性为测试目的生成高速的网络流量:上下文切换的负载不再出现,因此性能显著性的变好。
注意:该功能只在packet.dll中提供了辅助接口函数PacketSetNumWrites设置发送次数,而在wpcap.dll中并没有对应的函数接口。
在packet.dll中,提供单个数据包发送多次的函数接口,通过PacketSetNumWrites函数设置重复发送的次数,函数PacketSetNumWrites的源代码如下:
BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)
{
DWORD BytesReturned;
BOOLEAN Result;
if(AdapterObject->Flags != INFO_FLAG_NDIS_ADAPTER)
{
//
未明设备类型,函数返回
return FALSE;
}
Result = (BOOLEAN)DeviceIoControl(AdapterObject->hFile,
BIOCSWRITEREP,&nwrites,4,NULL,0,&BytesReturned,NULL);
return Result;
通过DeviceIoControl系统调用设置重复次数,重复发送实际上是在NPF的NPF_Write函数中执行的,参见下节的代码分析。
系统调用函数DeviceIoControl()对一个特定的设备驱动程序发送一个控制码,导致对应的设备执行相应的操作。该函数原型如下:
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
其中各参数的含义如下:
hDevice
输入参数,执行操作的设备句柄, PacketSetNumWrites()函数中传入AdapterObject->hFile值,为所打开的NPF适配器的句柄。
dwIoControlCode
输入参数,控制码,PacketSetNumWrites()函数中传入BIOCSWRITEREP值,来设置冲发次数。
lpInBuffer
输入参数,指向包含操作所需输入参数的内存区。PacketSetNumWrites()函数中传入nwrites变量的的起始地址,该变量储存了重发的次数。
nInBufferSize
输入参数,输入参数内存区的字节数,PacketSetNumWrites()函数中传入的值为4,也就是nwrites变量所占的字节数。
lpOutBuffer
输出参数,指向接收操作返回数据的输出内存区。PacketSetNumWrites()函数中不用该参数,为NULL。
nOutBufferSize
输入参数,输出参数内存区的字节数, PacketSetNumWrites()函数中不用该参数,为0。
lpBytesReturned
输出参数,存储在输出参数内存区中的数据字节数, PacketSetNumWrites()函数中传入BytesReturned变量的的起始地址,该变量返回输出参数内存区的数据字节数。
lpOverlapped
输入参数,指向一个OVERLAPPED 结构体的指针。如果hDevice 没有使用 FILE_FLAG_OVERLAPPED表示打开,就不用理会lpOverlapped 。PacketSetNumWrites()函数中不用该参数,为NULL。
如果DeviceIoControl函数成功,返回非0值,否则返回0。 PacketSetNumWrites()函数并不对返回值进行检查,而是直接返回该值,由更上层的函数执行检查。