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.2.3 不同接收方式的比较 - 图1

图 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.2.3 不同接收方式的比较 - 图2

用户空间文件转储方式存储数据包的测试数据结果如表14-5所示。

14.2.3 不同接收方式的比较 - 图3

4.通过内核空间文件转储的方式存储数据包

该方式实例程序,发送方还是使用send_queue.exe程序,具体实现参见[ch14/send_queue工程]。接收方的程序为kdump.exe,具体实现参见[ch14/kdump工程]。

kdump的命令格式如下:


kdump.exe存储文件数据容量大小数据包个数


上述代码中,参数[数据容量大小]为存储文件的最大容量,如果设为0,则以参数[数据包个数]为准。

实例中的具体命令如表14-6所示,其中由于可能存在掉包的情况,发送方发送的数据包个数应该多于实际预期接收的数据包个数。

14.2.3 不同接收方式的比较 - 图4

内核空间文件转储方式存储数据包的测试数据结果如表14-7所示。

14.2.3 不同接收方式的比较 - 图5

在接收大量数据包(如一千万个数据包)的情况下,通过对不同数据包接收处理方式的比较,可得出如下结论:

❑采用Wireshark工具接收并直接显示数据包的方式是无法满足要求的,将出现工具软件自身崩溃的问题。

❑采用文件转储的方式基本满足要求,不过存在少量的掉包现象。在同等条件下,内核转储方式掉包现象更少。