8.2.2 单个数据包发送多次的实现
在发送单个数据包的实现中,每发送一个数据包,用户空间的应用程序就需要一次WriteFile系统调用,以便通过内核驱动程序执行数据包的发送。而这会导致网络数据包的发送效率较低。正因为如此,为了满足生成大的网络流量、高网络带宽利用率的需要,WinPcap提供了使用一次WriteFile系统调用就能把单个数据包重复发送多次的功能。该重复发送的功能是在内核中实现的,由于上下文切换的负载不再出现,因此性能得到了显著性的提升,所以数据包的发送效率非常高。该功能通过用户空间的应用程序设置单个数据包重复发送的次数来实现。例如设为1000,那么,应用程序发送的每个原始数据包,在内核驱动程序中都将会重复发送1000次。在测试中,可使用该特性生成高速网络流量。不过该功能只能对数据包内容进行简单的、机械性的重复。
注意,目前只有Packet.dll库中提供的PacketSetNumWrites辅助接口函数才能实现重复发送功能,而在wpcap.dll库中并没有对应的函数。所以,此处对wpcap.dll库中单个数据包在内核中重复发送多次的情况不作分析,可以参见第13章的相关内容了解添加函数pcap_set_num_write在wpcap.dll库中实现的重复发送功能。
单个数据包重复发送多次与单个数据包发送一次的实现类似,除了需要增加对单个数据包发送次数的设置外,其余都一样。图8-11显示了设置发送次数的重要函数调用关系。
图 8-11 设置单个数据包重复发送次数的重要函数调用关系图
1.Packet.dll库中单个数据包发送多次的实现
在Packet.dll库中,提供了设置单个数据包重复发送多次的函数,即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;
}
PacketSetNumWrites函数通过DeviceIoControl系统调用设置重复次数,前面介绍过,重复发送实际上是在NPF的NPF_Write函数中执行的。
2.内核空间中设置重复发送次数
在PacketSetNumWrites函数中,可调用DeviceIoControl接口函数来设置重复次数。在内核驱动程序NPF中,设置重复次数实际上是在NPF_IoControl函数中修改Open->Nwrites成员的值实现的,NPF_IoControl函数中相应的代码如下:
/设置数据包重复发送的次数/
case BIOCSWRITEREP:
if(IrpSp->Parameters.DeviceIoControl.
InputBufferLength<sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
//设置重复发送次数
Open->Nwrites=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
SET_RESULT_SUCCESS(0);
break;
上面的代码可完成对Open->Nwrites成员值的修改。重复发送多次的功能最终是在NPF_Write函数中根据Open->Nwrites的值来实现的,相关代码如下:
NTSTATUS NPF_Write(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
……
NumSends=Open->Nwrites;
……
numSentPackets=0;
/进入重复发送数据包的while循环中/
While(numSentPackets<NumSends)
{
……//成功发送一次数据包
numSentPackets++;//已发数据包增加1个
……
}
……
}