《2022年2022年计算机网络程序设计 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年计算机网络程序设计 .pdf(22页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、ping 程序设计ping 命令是使用频率极高的一个网络测试命令,用以测试从一个主机到另一个主机间的网络上否可达。windows 自带的 ping 命令具有强大的功能,它有很多选项用于实现不同的测试目的。本章模仿windows 的 ping 命令,用c 语言实现了一个简单的命令。本章着重讲述 ping 命令的实现原理和c 语言的网络编程方法。读者可以在本章的基础上,对本章实现的 ping 命令进行扩展,开发出功能更强大、更完善的ping 命令, 并进一步掌握网络编程的方法。9.1 设计目的本章通过设计Ping 程序,讲解Ping 程序的实现原理,并初步讲解了c 语言网络编程技术。本章涉及很多网
2、络编程函数和编程技巧。包括库文件的导入; winsock 的初始化、 注销;socket的创建、关闭;设置socket 选项;根据主机名获取IP 地址;从堆中分配一定数量的空间、释 放 从 堆 中 分 配 的 空 间 ; 获 取 当 前 进 程ID号 ; 数 据 报 的 发 送 ; 数 据 报 的 接 等。通过本程序的训练,使读者对网络编程有一定的了解,掌握Ping 程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。9.2 功能描述本章用c 语言实现的ping命令,能用于测试一个主机到另一个主机间的联通情况,程序还提供了几个选项以实现不同的功能。(1)实现 ping 功能。
3、程序能实现基本的ping 操作,发送ICMP 回显请求报文,接收显应答报文。(2)能记录路由。程序提供了“-r ”选项,用以记录从源主机到目的主机的路由。(3)能输出指定条数的记录。程序提供了“-n”选项,用以输出指定条数的记录。(4)能按照指定大小输出每条记录。程序提供了“datasize ”选项,用以指定输出的数据报的大小。(5)能输出用户帮助。程序提供了用户帮助,显示程序提供的选项以及选项格式等。9.3 总体设计9.3.1 功能模块设计1. 功能模块图本系统共有4 个模块,分别是初始化模块、功能控制模块、数据控制模块、数据报解读模块和ping 测试模块,如图9.1 所示。各模块功能描述如
4、下。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 22 页 - - - - - - - - - 图 9.1 系统模块图(1) 初始化模块。 改模块用于初始化各个全局变量,为全局变量赋初始值;初始化, 加载库。(2)功能控制模块。改模块是被其它模块调用,其功能包括获取参数、计算校验和填充数据报文、释放占用资源和显示用户帮助。(3)数据报解读模块。改模块用于解读接收到的报文和选项。(4)测试模块。改模块是本程序的核心模块,调用其他模块实现其功能,主要是实现的功能。2系统流程
5、图系统执行的流程图9.2 所示。程序首先调用IniPing() 函数初始化各全局变量,然后GetArgments() 函数获取用户输入的参数,检查用户输入的参数,如果参数不正确或者没有输入参数,则显示用户帮助信息(User help ) ,并结束程序;如果参数正确,则对指定目的地执行 Ping 命令,如果 Ping 通,则显示Ping 结果并释放占用资源,如果没有Ping 通,则报告错误信息,并释放占用资源。Ping 程序设计初始化模块数据报解读模块功能控制模块Ping 测试模块名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名
6、师精心整理 - - - - - - - 第 2 页,共 22 页 - - - - - - - - - 图 9.2 系统流程图3.参数获取( GetArgments() 函数)流程图获取的参数包括“-r ” (记录路由) 、 “-n” (记录条数程序,任意的整数)和datasize( 数据报大小 )。程序首先判断每一个参数的第一字符,如果第一个字符是“-” (短横线),则认为是“ -r ”或者“ -n”中的一个,然后作进一步判断。如果该参数的第二个字符是数字,则判断该参数为记录的条数,如果该参数的第二个字符是“r” ,则判断该参数为“-r ” , 用于开始初始化个变量获取参数信息输入参数是否正确
7、?Ping 目的地Ping 成功?输出 Ping 结果释放占用资源结束输出错误信息显示帮助信息名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 22 页 - - - - - - - - - 记录路由;如果参数的第一个字符是数字,则认为参数是IP 地址;或者datasize,然后作进一步的判断。如果该参数中不存在非数字的字符,则判断该参数为datasize ;如果存在非数字的字符,则判断该参数为IP 地址;其他情况则判断为主机名。参数获取的流程如图 9.3 所示。图 9.3
8、参数获取流程图开始Argc=1检查第一i 个参数的第一个字符是 “-”?检查第一 i 个参数的第二个字符是数字?该参数表示要获取的记录数转换成十进制记录到全局变量 packetNUM 还有参数?结束是数字?该 参 数 中 有非 数 字 字该参数表示IP 地址该参数表示数据报大小是“r ”? 显示用户帮助设标志位 Record Flag 为 ture I=i+1 记录到变量Lpdest 中记录到变量Datasize 中名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 22 页
9、 - - - - - - - - - 4.ping() 函数流程图ping() 函数是本程序的核心部分它调用其他模块的函数来实现,其主要步骤包括创建接字,设置路由选项(如果需要的话)、设置接收和发送超时值、名字解析(如果需要的话)、分配内存、创建ICMP 报文、发送ICMP 请求报文、接收ICMP应答报文和解读ICMP报文。其执行流程如图9.4 所示。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 22 页 - - - - - - - - - 开始创建原始套接字创建成功?
10、记录路由?设置接收和发送超时值为每个 ICMP 设置路由选项设置成功?名字解析?根据主机名获取各种参数获取成功?设置目的地址各项字段根据 ICMP 报文大小分配内存分配成功创建 ICMP 报文发送 ICMP 请求发送成功?超时发送?输出超时发送接收 ICMP 应答输出失败信息名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 22 页 - - - - - - - - - 图 9.4 Ping 函数流程图9.3.2 数据结构设计本程序定义了3 个结构体: -iphdr 、-ic
11、mphdr 、和 -ipotionhdr ,分别用于存放IP 报头信息、 ICM P 报头信息和IP 路由选项信息。1.定义 IP 报头结构体Typedef struct _iphdr Unsigned int h_len:4; Unsigned int version:4; Unsigned char tos; Unsigned short total_len; Unsigned short ident; Unsigned short frag_flags; Unsigned char ttl; Unsigned chor proto; Unsigned short checksum; Un
12、signed int sourceIP; Unsigned int destIP; IpHeader; 接收成功?超时接收?输出失败信息输出超时接收读取 ICMP 数据报文记录数达到指定值?名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 22 页 - - - - - - - - - 其中各字段表示意义如下。h-len:4 : 表示 IP 报头长度, 首部长度指的是首部占32bit 字的数目, 包括任何选项。由于它是一个4bit 字段,因此首部最长为60 个字节,不包括任何
13、选项的IP 报头是 20 个字节。Version:4: 表示 IP 的版本号,这里表示Ipv4. 。Top: 表示服务的类型,可以表示最小时延,最大吞吐量,最高可靠性和最小费用。Total len: 整个 IP 数据报的总长度。Ident: 唯一的标识符,标识主机发送的每一份数据报。Frag-flags: 分段标志,表示过长的数据报是否要分段。Ttl: 生存期,表示数据报可以经过的最多路由器数。Proto: 协议类型( TCP 、UDP 等) 。Checksum: 校验和。sourceIP: 源 IP 地址。destIP: 目的 IP 地址。2.定义报头结构体Typedef struct ic
14、mphdr BYTE i_type; BYTE i_code : USHORT i_cksum; USHORT i_id; USHORT i_seq; ULONG timestamp; IcmpHeader; 其中各字段表示意义如下。I_tye : 报文类型。I_code : 该类型中的代码号,一种ICMP 报文的类型号和该类型中的代码号共同决定。 、I_cksum: 校验和。I_seq: 序列号,序列号从0 开始,每发送一次新的回显请求就加1. Timestamp: 时间。3.定义 IP 选项结构体Typedef struct _ipoptionhdr Unsigned char code;
15、 Unsigned char len; Unsigned char ptr; Unsigned loang addr9; IcmpHeader; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 22 页 - - - - - - - - - 其中各字段表示意义如下。Code: 指明 IP 选项类型,对于路由记录选项,它的值是7。Len: 选项头长度。Ptr: 地址指针字段,是一个基于1的指针,指向存放下一个IP 地址的位置。addr9: 记录的 Ip 地址列表,由于IP 首
16、部中选项的空间有限,所以可以记录的Ip 地址最多是9 个。9.33函数功能描述1) IntPing() 函数原型: void IntPing() IntPing() 函数用于初始化ping 所需的全局变量,为各个变量赋初始值。2)userHelp() 函数原型: void userHelp() userHelp() 函数用于显示用户帮助信息。当程序检查到参数错误或者没有必要的参数(如主机 IP 地址或者主机名)时,则会调用此函数显示帮助信息。3) GetArgments() 函数原型: void GetArgments(int argc, char*argv) GetArgments() 函数
17、用于获取用户提交的参数。其中argc 表示获取的参数个数,argv 用于存储获取的参数,这两个形参和主函数中的形参表示的意义一样的。4)checkSum() 函数原型: USHORT checkSum(USHORT *buffer,int size) checkSum() 函数用于计算校验和。计算过程是首先把数据报头中的校验和字段设置为 0,然后对首部中每个16bit 进行二字段进制反码求和(整个首部看成是由一串16bit的字组成),结果存在校验和字段中。其中 buffer 用于存放ICMP 数据, size 表示 ICMP报文大小。5)FillCMPData() 函数原型: void Fil
18、lCMPData() FillCMPData()函数用于填充ICMP 数据报中各个字段。其中icmp_data 表示 ICMP数据,datasize 表示 ICMP报文大小。6) reeRes() 函数原型: void reeRes() reeRes()函数用于释放占用的资源,包括关闭初始化socket 调用的函数的、关闭创建的socket 和释放分配的内存等。7)DecodeIPOptions() 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 22 页 - - - -
19、 - - - - - 函数原型: void DecodeIPOptions() DecodeIPOptions() 函数用于解读IP 选项,从中读出从源主机到目的主机经过的路由,并输出路由信息。Buf 表示存放接收到的ICMP 报文的缓冲区,bytes 表示接收到的字节数。8)DecodelICMPHeader() 函数原型: void DecodelICMPHeader(char*buf,int bytes,SOCKADDR_IN*from) DecodelICMPHeader()函数用于解读ICMP报文信息。 Buf 表示存放接收到的ICMP报文的缓冲区, bytes 表示接收到的字节数,
20、from 表示发送ICMP回显应答的主 机IP地址。9)PingTest() 函数原型: void PingTest(int timeout) PingTest() 函数用于进行Ping 操作。其中timeout 表示设定的发送超时值。9.4程序实现9.1.4 源码分析1. 程序预处理/*导入库文件 */ #pragma comment( lib, ws2_32.lib ) /*加载头文件 */ #include #include #include #include #include /*定义常量 */ /*表示要记录路由*/ #define IP_RECORD_ROUTE 0 x7 /*默认
21、数据报大小*/ #define DEF_PACKET_SIZE 32 /*最大的 ICMP 数据报大小 */ #define MAX_PACKET 1024 /*最大 IP 头长度 */ #define MAX_IP_HDR_SIZE 60 /*ICMP报文类型,回显请求*/ #define ICMP_ECHO 8 /*ICMP报文类型,回显应答*/ #define ICMP_ECHOREPLY 0 /*最小的 ICMP 数据报大小 */ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - -
22、第 10 页,共 22 页 - - - - - - - - - #define ICMP_MIN 8 /*自定义函数原型*/ void InitPing(); void UserHelp(); void GetArgments(int argc, char* argv); USHORT CheckSum(USHORT *buffer, int size); void FillICMPData(char *icmp_data, int datasize); void FreeRes(); void DecodeIPOptions(char *buf, int bytes); void Decod
23、eICMPHeader(char *buf, int bytes, SOCKADDR_IN* from); void PingTest(int timeout); /*IP 报头字段数据结构*/ typedef struct _iphdr unsigned int h_len:4; /*IP 报头长度 */ unsigned int version:4; /*IP 的版本号 */ unsigned char tos; /*服务的类型 */ unsigned short total_len; /* 数据报总长度*/ unsigned short ident; /*惟一的标识符*/ unsigne
24、d short frag_flags; /*分段标志 */ unsigned char ttl; /*生存期 */ unsigned char proto; /* 协议类型 (TCP 、UDP 等 )*/ unsigned short checksum; /* 校验和 */ unsigned int sourceIP; /*源 IP 地址 */ unsigned int destIP; /*目的 IP 地址 */ IpHeader; /*ICMP报头字段数据结构*/ typedef struct _icmphdr BYTE i_type; /*ICMP报文类型 */ BYTE i_code;
25、/* 该类型中的代码号*/ USHORT i_cksum; /* 校验和 */ USHORT i_id; /* 惟一的标识符*/ USHORT i_seq; /* 序列号 */ ULONG timestamp; /*时间戳 */ IcmpHeader; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 22 页 - - - - - - - - - /*IP 选项头字段数据结构*/ typedef struct _ipoptionhdr unsigned char code
26、; /*选项类型 */ unsigned char len; /*选项头长度 */ unsigned char ptr; /*地址偏移长度*/ unsigned long addr9; /* 记录的 IP 地址列表 */ IpOptionHeader; /*定义全局变量*/ SOCKET m_socket; IpOptionHeader IpOption; SOCKADDR_IN DestAddr; SOCKADDR_IN SourceAddr; char *icmp_data; char *recvbuf; USHORT seq_no ; char *lpdest; int datasize
27、; BOOL RecordFlag; double PacketNum; BOOL SucessFlag; 2.初始化模块/*初始化变量函数*/ void InitPing() WSADATA wsaData; icmp_data = NULL; seq_no = 0; recvbuf = NULL; RecordFlag = FALSE; lpdest = NULL; datasize = DEF_PACKET_SIZE; PacketNum = 5; SucessFlag = FALSE; /*Winsock初始化 */ if (WSAStartup(MAKEWORD(2, 2), &ws
28、aData) != 0) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 22 页 - - - - - - - - - /*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/ printf(WSAStartup() failed: %dn, GetLastError(); return ; m_socket = INV ALID_SOCKET; 3.功能控制模块/*显示信息函数*/ void UserHelp() printf(UserHelp:
29、 ping -r data sizen); printf( -r record routen); printf( -n record amountn); printf( host remote machine to pingn); printf( datasize can be up to 1KBn); ExitProcess(-1); /*获取 ping 选项函数 */ void GetArgments(int argc,char* argv) int i; int j; int exp; int len; int m; /* 如果没有指定目的地地址和任何选项*/ if(argc = 1)
30、printf(nPlease specify the destination IP address and the ping option as follow!n); UserHelp(); for(i = 1; i =1;j-,exp+) /*根据 argvij中的 ASCII 值计算要获取的记录条数(十进制数 )*/ PacketNum += (double)(argvij-48)*pow(10,exp); else switch (tolower(argvi1) /*选项指示要获取路由信息*/ case r: RecordFlag = TRUE; break; /*没有按要求提供选项*/
31、 default: UserHelp(); break; /*参数是数据报大小或者IP 地址 */ else if (isdigit(argvi0) for(m=1;m 1) cksum += *buffer+; size -= sizeof(USHORT); if (size) cksum += *(UCHAR*)buffer; /*对每个 16bit 进行二进制反码求和*/ cksum = (cksum 16) + (cksum & 0 xffff); cksum += (cksum 16); return (USHORT)(cksum); /*填充 ICMP 数据报字段函数*/ void
32、 FillICMPData(char *icmp_data, int datasize) IcmpHeader *icmp_hdr = NULL; char *datapart = NULL; icmp_hdr = (IcmpHeader*)icmp_data; /*ICMP报文类型设置为回显请求*/ icmp_hdr-i_type = ICMP_ECHO; icmp_hdr-i_code = 0; /*获取当前进程IP 作为标识符 */ icmp_hdr-i_id = (USHORT)GetCurrentProcessId(); icmp_hdr-i_cksum = 0; icmp_hdr-
33、i_seq = 0; datapart = icmp_data + sizeof(IcmpHeader); /*以数字 0 填充剩余空间*/ memset(datapart,0,datasize-sizeof(IcmpHeader); /*释放资源函数*/ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 15 页,共 22 页 - - - - - - - - - void FreeRes() /*关闭创建的套接字*/ if (m_socket != INVALID_SOCKET) c
34、losesocket(m_socket); /*释放分配的内存*/ HeapFree(GetProcessHeap(), 0, recvbuf); HeapFree(GetProcessHeap(), 0, icmp_data); /*注销 WSAStartup() 调用 */ WSACleanup(); return ; 4.数据报解读模块/*解读 IP 选项头函数 */ void DecodeIPOptions(char *buf, int bytes) IpOptionHeader *ipopt = NULL; IN_ADDR inaddr; int i; HOSTENT *host =
35、 NULL; /*获取路由信息的地址入口*/ ipopt = (IpOptionHeader *)(buf + 20); printf(RR: ); for(i = 0; i ptr / 4) - 1; i+) inaddr.S_un.S_addr = ipopt-addri; if (i != 0) printf( ); /*根据 IP 地址获取主机名*/ host = gethostbyaddr(char *)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr), AF_INET); /*如果获取到了主机名,则输出主机名*/ if (host) pr
36、intf(%-15s) %sn, inet_ntoa(inaddr), host-h_name); /*否则输出IP 地址 */ else 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 16 页,共 22 页 - - - - - - - - - printf(%-15s)n, inet_ntoa(inaddr); return; /*解读 ICMP 报头函数 */ void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN *fr
37、om) IpHeader *iphdr = NULL; IcmpHeader *icmphdr = NULL; unsigned short iphdrlen; DWORD tick; static int icmpcount = 0; iphdr = (IpHeader *)buf; /*计算 IP 报头的长度 */ iphdrlen = iphdr-h_len * 4; tick = GetTickCount(); /*如果 IP 报头的长度为最大长度(基本长度是20 字节 ),则认为有IP 选项,需要解读IP 选项 */ if (iphdrlen = MAX_IP_HDR_SIZE) &
38、 (!icmpcount) /*解读 IP 选项,即路由信息*/ DecodeIPOptions(buf, bytes); /*如果读取的数据太小*/ if (bytes sin_addr); icmphdr = (IcmpHeader*)(buf + iphdrlen); /*如果收到的不是回显应答报文则报错*/ if (icmphdr-i_type != ICMP_ECHOREPLY) printf(nonecho type %d recvdn, icmphdr-i_type); return; /*核实收到的ID 号和发送的是否一致*/ if (icmphdr-i_id != (USHO
39、RT)GetCurrentProcessId() printf(someone elses packet!n); return ; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 17 页,共 22 页 - - - - - - - - - SucessFlag = TRUE; /*输出记录信息*/ printf(%d bytes from %s:, bytes, inet_ntoa(from-sin_addr); printf( icmp_seq = %d. , icmphdr-i_
40、seq); printf( time: %d ms, tick - icmphdr-timestamp); printf(n); icmpcount+; return; 5.Ping 测试模块/*ping 函数 */ void PingTest(int timeout) int ret; int readNum; int fromlen; struct hostent *hp = NULL; /*创建原始套接字,该套接字用于ICMP 协议 */ m_socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVER
41、LAPPED); /*如果套接字创建不成功*/ if (m_socket = INVALID_SOCKET) printf(WSASocket() failed: %dn, WSAGetLastError(); return ; /*若要求记录路由选项*/ if (RecordFlag) /*IP 选项每个字段用0 初始化 */ ZeroMemory(&IpOption, sizeof(IpOption); /*为每个 ICMP 包设置路由选项*/ IpOption.code = IP_RECORD_ROUTE; IpOption.ptr = 4; 名师资料总结 - - -精品资料欢迎下载 -
42、 - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 18 页,共 22 页 - - - - - - - - - IpOption.len = 39; ret = setsockopt(m_socket, IPPROTO_IP, IP_OPTIONS,(char *)&IpOption, sizeof(IpOption); if (ret = SOCKET_ERROR) printf(setsockopt(IP_OPTIONS) failed: %dn,WSAGetLastError(); /*设置接收的超时值*/ readNum
43、= setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout, sizeof(timeout); if(readNum = SOCKET_ERROR) printf(setsockopt(SO_RCVTIMEO) failed: %dn,WSAGetLastError(); return ; /*设置发送的超时值*/ timeout = 1000; readNum = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO,(char*)&timeout, sizeof(timeout); if
44、(readNum = SOCKET_ERROR) printf(setsockopt(SO_SNDTIMEO) failed: %dn,WSAGetLastError(); return ; /*用 0 初始化目的地地址*/ memset(&DestAddr, 0, sizeof(DestAddr); /*设置地址族,这里表示使用IP 地址族 */ DestAddr.sin_family = AF_INET; if (DestAddr.sin_addr.s_addr = inet_addr(lpdest) = INADDR_NONE) /*名字解析,根据主机名获取IP 地址 */ if (hp
45、 = gethostbyname(lpdest) != NULL) /*将获取到的IP 值赋给目的地地址中的相应字段*/ memcpy(&(DestAddr.sin_addr), hp-h_addr, hp-h_length); /*将获取到的地址族值赋给目的地地址中的相应字段*/ DestAddr.sin_family = hp-h_addrtype; printf(DestAddr.sin_addr = %sn, inet_ntoa(DestAddr.sin_addr); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师
46、精心整理 - - - - - - - 第 19 页,共 22 页 - - - - - - - - - /*获取不成功 */ else printf(gethostbyname() failed: %dn,WSAGetLastError(); return ; /*数据报文大小需要包含ICMP报头 */ datasize += sizeof(IcmpHeader); /*根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存的内容将被初始化为 0*/ icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_
47、PACKET); recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET); /*如果分配内存不成功*/ if (!icmp_data) printf(HeapAlloc() failed: %dn, GetLastError(); return ; /* 创建 ICMP 报文 */ memset(icmp_data,0,MAX_PACKET); FillICMPData(icmp_data,datasize); while(1) static int nCount = 0; int writeNum;
48、/*超过指定的记录条数则退出*/ if (nCount+ = PacketNum) break; /*计算校验和前要把校验和字段设置为0*/ (IcmpHeader*)icmp_data)-i_cksum = 0; /*获取操作系统启动到现在所经过的毫秒数,设置时间戳*/ (IcmpHeader*)icmp_data)-timestamp = GetTickCount(); /*设置序列号 */ (IcmpHeader*)icmp_data)-i_seq = seq_no+; /*计算校验和 */ (IcmpHeader*)icmp_data)-i_cksum = CheckSum(USHOR
49、T*)icmp_data, 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 20 页,共 22 页 - - - - - - - - - datasize); /*开始发送ICMP 请求*/ writeNum = sendto(m_socket, icmp_data, datasize, 0,(struct sockaddr*)&DestAddr, sizeof(DestAddr); /*如果发送不成功*/ if (writeNum = SOCKET_ERROR) /*如果是由于超时不
50、成功*/ if (WSAGetLastError() = WSAETIMEDOUT) printf(timed outn); continue; /*其他发送不成功原因*/ printf(sendto() failed: %dn, WSAGetLastError(); return ; /*开始接收ICMP 应答*/ fromlen = sizeof(SourceAddr); readNum = recvfrom(m_socket, recvbuf, MAX_PACKET, 0,(struct sockaddr*)&SourceAddr, &fromlen); /*如果接收不成功*/ if (