14.2.3 不同接收方式的比较
在发送端以异步方式连续发送1000万个数据包,每个数据包的长度为1514字节,在接收方以不同的接收方式接收所发送的数据包,从而测试不同接收方式的区别。具体可采用下面三种不同的接收方式:
❑直接使用Wireshark工具来接收数据包,并显示数据包内容。
❑通过用户空间的文件转储方式存储数据包到文件中,然后读取转储文件分析是否存在数据包掉包的现象。
❑通过内核空间的文件转储方式存储数据包到文件中,然后读取转储文件分析是否存在数据包掉包的现象。
发送方使用[ch14/send_queue工程]的程序执行数据包发送,发送命令如下:
send_queue.exe 1514 10000000 0
接下来分别查看各种接收方式的测试结果。
1.使用Wireshark工具接收数据包并显示
接收端采用Wireshark软件(Version 1.0.2)接收数据包,在接收到3241922个数据包时出现程序崩溃,如图14-15所示。
图 14-15 Wireshark崩溃
注意,Wireshark软件出现该错误后,应该删除C:\Documents and Settings\Administrator\Local Settings\Temp\目录下名称类似于etherxxxxa00296的文件,该文件大小约7GB。如果不删除该文件,将会耗尽磁盘空间。
2.文件转储时分析数据是否掉包的方法
发送大量数据包时,为了分析接收方是否存在数据包掉包的现象,可在发送方与接收方分别采用如下操作来实现该分析。
(1)发送方
在发送方可使用[ch14/send_queue工程]发送数据包。在数据包的第14、15、16、17字节中存储每个包的序号,从0开始计数。同时在第12、13字节中存储特定的协议编号(0x0c0d)。以同一数据包重复发送多次的方式无法更新数据包的序号,所以此处以发送队列异步方式发送。
生成合适数据包的代码如下,完整的代码见[ch14/send_queue工程]。
/生成数据包/
void gen_packet(unsigned char*buf,int len,int count)
{
int i=0;
//设置目标MAC地址为:01:01:01:01:01
for(i=0;i<6;i++)
{
buf[i]=0x01;
}
//设置源MAC地址为:02:02:02:02:02
for(i=6;i<12;i++)
{
buf[i]=0x02;
}
//设置协议标识为xc0xd,无任何实际意义
buf[12]=0xc;
buf[13]=0xd;
if(count>=0)
{
//填充数据包的序号
memcpy(buf+14,&count,sizeof(count));
//填充数据包的内容
for(i=18;i<len;i++)
{
buf[i]=i-18;
}
}else
{
//填充数据包的内容
for(i=14;i<len;i++)
{
buf[i]=i-14;
}
}
}
(2)接收方
首先通过文件转储的方式存储数据包,使用[ch14/SaveDumpFile工程]或[ch14/kdump工程]代码。然后从文件中读取数据包,使用[ch14/ReadDumpFile工程]代码进行是否掉包的分析。
在[ch14/ReadDumpFile工程]的实现中,首先检查协议字段是否符合发送方所指定的协议字段值,接着对符合协议要求的数据包分析数据包的序号是否递增,否则显示错误的数据包序号。
通过发送方与接收方的相互配合,可很容易地判断是否存在数据包掉包的现象。
下面是[ch14/ReadDumpFile工程]的具体实现:
defne WIN32
defne HAVE_REMOTE
include<stdio.h>
include<pcap.h>
void dispatcher_handler(u_char,const struct pcap_pkthdr,const u_char*);
struct user_param
{
int cur_num;//当前数据包个数
pcap_t*src_fp;//dump文件
timeval tv_begin;//记录第一个数据包的接收时间
timeval tv_end;//记录最后一个数据包的接收时间
};
int main(int argc,char**argv)
{
pcap_if_t*alldevs;
pcap_if_t*d;
int inum;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
char source[PCAP_BUF_SIZE];
struct user_param uparam;
uparam.cur_num=0;
if(argc!=2){
printf("usage:%s flename",argv[0]);
return-1;
}
/根据新WinPcap语法创建一个源字符串/
if(pcap_createsrcstr(
source,//源字符串
PCAP_SRC_FILE,//要打开的文件
NULL,//远程主机
NULL,//远程主机端口
argv[1],//要打开的文件名
errbuf//错误缓冲区
)!=0)
{
fprintf(stderr,"\nError creating a source string\n");
return-1;
}
/打开输入的源dump文件/
if((uparam.src_fp=pcap_open(
source,//设备名
65536,//要捕捉的数据包的部分
//65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS,//混杂模式
1000,//读取超时时间
NULL,//远程机器验证
errbuf//错误缓冲池
))==NULL)
{
fprintf(stderr,"\nUnable to open the fle%s.\n",
source);
return-1;
}
//读取并解析数据包,直到EOF为真
pcap_loop(uparam.src_fp,0,
dispatcher_handler,(u_char*)&uparam);
/显示数据包总数/
fprintf(stderr,"process packet number is:%d\n",
uparam.cur_num);
/计算接收所有数据包所花的时间,并显示/
foat dus=(
(uparam.tv_end.tv_sec-uparam.tv_begin.tv_sec)*1000000
+(uparam.tv_end.tv_usec-uparam.tv_end.tv_usec)
)/1000000.0;
printf("times is%f s\n",dus);
/释放资源/
pcap_close(uparam.src_fp);
return 0;
}
void dispatcher_handler(u_char*param,
const struct pcap_pkthdrheader,const u_charpkt_data)
{
int ret=-1;
struct user_parampuser_param=(struct user_param)param;
int packet_num=-1;
if((pkt_data[12]==0xc)&&(pkt_data[13]==0xd))
{//协议正确
memcpy(&packet_num,pkt_data+14,sizeof(packet_num));
if(packet_num>=0)
{
if(puser_param->cur_num==0)
{
puser_param->tv_begin=header->ts;
}
if(packet_num==puser_param->cur_num)
{
//没有数据包丢失
puser_param->cur_num++;
}
else
{
//数据包丢失
if(packet_num-puser_param->cur_num==1)
printf("No.%d packet is lost.\n",
puser_param->cur_num);
else
printf("No.[%d-%d]packets are lost.",
puser_param->cur_num,packet_num-1);
puser_param->cur_num=packet_num+1;
}
puser_param->tv_end=header->ts;
}
/显示处理提示信息/
if(puser_param->cur_num%50000==0)
{
printf("process packet is:%d.\n",
puser_param->cur_num);
}
}
}
3.通过用户空间文件转储方式存储数据包
发送方的程序为send_queue.exe,具体实现参见[ch14/send_queue工程]。
接收方的程序为SaveDumpFile.exe,具体实现参见[ch14/SaveDumpFile工程]。
SaveDumpFile的命令使用格式如下:
SaveDumpFile.exe存储文件数据包个数
测试所涉及的具体命令如表14-4所示。因为可能存在掉包的情况,发送方发送的数据包个数应该多于实际预期接收的数据包个数。
用户空间文件转储方式存储数据包的测试数据结果如表14-5所示。
4.通过内核空间文件转储的方式存储数据包
该方式实例程序,发送方还是使用send_queue.exe程序,具体实现参见[ch14/send_queue工程]。接收方的程序为kdump.exe,具体实现参见[ch14/kdump工程]。
kdump的命令格式如下:
kdump.exe存储文件数据容量大小数据包个数
上述代码中,参数[数据容量大小]为存储文件的最大容量,如果设为0,则以参数[数据包个数]为准。
实例中的具体命令如表14-6所示,其中由于可能存在掉包的情况,发送方发送的数据包个数应该多于实际预期接收的数据包个数。
内核空间文件转储方式存储数据包的测试数据结果如表14-7所示。
在接收大量数据包(如一千万个数据包)的情况下,通过对不同数据包接收处理方式的比较,可得出如下结论:
❑采用Wireshark工具接收并直接显示数据包的方式是无法满足要求的,将出现工具软件自身崩溃的问题。
❑采用文件转储的方式基本满足要求,不过存在少量的掉包现象。在同等条件下,内核转储方式掉包现象更少。