ping命令的设计与实现要点.pdf
《ping命令的设计与实现要点.pdf》由会员分享,可在线阅读,更多相关《ping命令的设计与实现要点.pdf(21页珍藏版)》请在三一文库上搜索。
1、设计报告 课程计算机网络 设计名称ping 命令的设计与实现 专业班级计科 094 同组人姓名 同组人学号 实验日期2013-04-10 指导教师 成绩 2013 年 04 月 10 日 设计目的和要求 1、实验目的: Ping 命令向目的主机发送ICMP ECHO REQUEST 请求并接收目的主机返回的响 应报文,用来检验本地主机和远程的主机是否连接。 2.实验要求: 利用 ICMP数据包,测试主机的连通性, 通过课程设计, 使学生熟悉ICMP报文结构, 使学生对 ICMP有更深的理解。 要求 : 输出参考系统自带ping 程序,命令行运行 :ping ip 二、设计说明 设计分析: 使用
2、原始套接字可以读写ICMP分组,利用原始套接字发送ICMP回显请求, 并接收 ICMP 回显应答,通过icmp_send ()发送 ICMP回显示请求包,icmp_recv ()接收 ping 目的主 机的回复, 并使用终端信号处理函数SIGINT 处理信号, 建立两个线程, 一个用于发送数据, 另一个用于接收响应数据,主程序等待两个线程运行完毕后再进行下一步动作。最后, 主程 序讲发送数据和接收的数据进行统计,并将结果打印出来。 系统运行环境: 虚拟机 :Fedora14 (linux操作系统) gcc 设计中的重点和难点: ICMP数据包的打包和解包,以及从CRC16 校验算法的分析实现
3、输入和输出条件: 在 linux系统下运行ping 在出现 4 个响应包后按Ctrl+c键停止发送。 三、系统详细设计 Ping 命令的设计与实现 Ping 命令向目的主机发送ICMP ECHO REQUEST 请求并接收目的主机返回的响应报 文,用来检验本地主机和远程的主机是否连接。 协议格式 图 1.1 中已经对协议的报文格式进行了说明。Ping 的客户端方式的类型为8, 代码值为0,表示 ICMP 的回显请求。类型为0,代码为0 是,是 ICMP 回显应答。检验和 为 16 为的crc16 的算法。 0 7 8 15 16 31 图 1.1 ICMP 报文的数据格式 图 1.2 所示为p
4、ing 所使用的类型和代码格式。包含16 位的标始符和16 为的序列号。 序列号是用于标识发送或者响应的序号,而标示符通常用于表明发送和接收此报的用户,一 眼用进程的PID 来识别。 0 7 8 15 16 31 图 1.2 ping 的数据格式 例如一个用户的进程PID 为 1000,发送了一个序列号为1 的回显请求报文,当此报文 被目的主机正确处理并返回后,可以用PID 来识别是否为当前的用户,并且用序列号来识 别哪个报文被返回,通过发送报文到目的主机并接受响应,可以计算发送和接收二者之间的 时间差,来判断网络的状况。 类型( 8 位)代码( 8 位)校验和( 16 位) 此部分不同的类型
5、和代码格式不同 类型 (8 或 0) 代码(0)校验和 标示符序列符 占位字节 如图 1.3 所示, ping 程序一般按照图中的框架进行设计。主要分为发送数据和接收数据 及计算时间差。 发送数据对组织好的数据进行发送,接收数据从网络上接收数据并判断其合 法性,例如判断是否本进程发出的报文等。 图 1.3 ping 程序的基本框架 由于 ICMP 必须使用原始套接字进行设计,要手动设置IP 的头部和ICMP 的头部 并进行校验。 开始 设 置 发 送 数据 计 算 机 发 送 数 据 校 发送数据 接收数据 计 算 时 速 差 解 包 判 断 正误 结束 校验和函数 TCP/IP 协议栈使用的
6、校验算法是比较经典的,对 16 为的数据进行累加计算,并返 回计算结果。 需要注意的是对奇数个字节数据的计算,是将最后的有效数据作为最高位 的字节,低字节填充了0。 /* CRC16 校验和计算icmp_cksum 参数: data:数据 len:数据长度 返回值: 计算结果, short 类型 */ static unsigned short icmp_cksum(unsigned char *data, int len) int sum=0;/* 计算结果*/ int odd = len /* 是否为奇数 */ unsigned short *value = (unsigned short
7、*)data; /*将数据按照2 字节为单位累加起来*/ while( len data += 2; len -=2; /*判断是否为奇数个数据,若ICMP 报头为奇数个字节,会剩下最后一字节。*/ if( odd) unsigned short tmp = (*data)16) + (sum sum += (sum 16) ; return sum; 设置 IP 发送报文的头部 ip 头部格式: struct ip #if _BYTE_ORDER = _LITTLE_ENDIAN /* 如果为小端*/ gned int ip_v:4; /* 版本*/ #endif #if _BYTE_ORD
8、ER = _BIG_ENDIAN /*如果为大端 */ unsigned int ip_v:4; /* 版本*/ unsigned int ip_hl:4; /* 头部长度*/ #endif u_int8_t ip_tos; /* TOS ,服务类型*/ u_short ip_len; /* 总长度*/ u_short ip_id; /* 标识值*/ u_short ip_off; * 段偏移值*/ u_int8_t ip_ttl; /* TTL ,生存时间*/ u_int8_t ip_p; /* 协议类型*/ u_short ip_sum; /* 校验和*/ struct in_addr i
9、p_src, ip_dst; /* 源地址和目的地址*/ ; 设置 ICMP 发送报文的头部 对于回显请求的ICMP 报文,下面是ICMP 结构简化形式: 即仅包含消息类型、消息代码、校验和、数据报的ID 、数据报的序列号即ICMP 数据 段几个部分。校验和的值在计算之前其他的值应该先进行填充,而校验和也需要设置为0 来占位,然后在计算真正的校验和值。 struct icmp u_int8_t icmp_type; /* 消息类型*/ u_int8_t icmp_code; /* 消息类型的子码*/ u_int16_t icmp_cksum; /* 校验和*/ union u_char ih_
10、pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* 网关地址*/ struct ih_idseq /* 显示数据报*/ u_int16_t icd_id; /* 数据报 ID */ u_int16_t icd_seq; /* 数据报的序号*/ ih_idseq; icmp_hun; #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq union struct u_int8_t id_data1; /* 数据*/ icmp
11、_dun; #define icmp_data icmp_dun.id_data ; ICMP回显得数据部分可以任意设置,但是以太网包的总长度不能小于以太网的最小 值,即总长度不能小于46,由于 IP 头部为 20 字节, ICMP 头部为 8 个字节,以太网头部占 用 14 个字节,因此ICMP 回显包的最小值为46-20-8-14=4 个字节。 ICMP 回显请求的类型为8,即 ICMP-ECHO 。 ICMP 回显请求的代码值为0. ICMP 回显请求的序列号是一个16 位的值,通常由一个递增的值生成。 ICMP 回显请求的ID 用于区别,通常用进程的PID 填充。 进行 ICMP 头部
12、校验的代码如下: 剥离 ICMP 接受报文的头部 函数 icmp_unpack() 用于剥离IP 头部,分析ICMP 头部的值。判断是否为正确的ICMP 报文,并打印结果。 参数 buf 为剥去了以太网部分数据的IP 数据报文, len 为数据长度。可以利用IP 头部 的参数快速地跳ICMP 报文部分, IP 结构的 ip_hl 标识 IP 头部的长度,由于ip_hl 标识的是 4 字节单位,所以需要乘以4 来获得 ICMP 段的地址。 获得 ICMP 数据段后,判断其类型是否为ICMP_ECHOREPL Y,并核实其标识是否为本进 程的 PID。 由于需要判断数据报文的往返时间,在本程序中需
13、要先查找这个包发送时的时间, 与当前时间进行计算后,可以得出本地主机与目标主机之间网络ICMP 回显报文的差值。 程序需要累加成功接收到的报文用于程序退出时的统计。 /*设置 ICMP 报头 */ static void icmp_pack(struct icmp *icmph, int seq, struct timeval *tv, int length ) unsigned char i = 0; /* 设置报头*/ icmph-icmp_type = ICMP_ECHO; /*ICMP 回显请求 */ icmph-icmp_code = 0; /*code 值为 0*/ icmph-i
14、cmp_cksum = 0; /*先将 cksum 值填写 0,便于之后的cksum 计 算*/ icmph-icmp_seq = seq; /*本报的序列号*/ icmph-icmp_id = pid /*填写 PID*/ for(i = 0; iicmp_datai = i; /* 计算校验和*/ icmph-icmp_cksum = icmp_cksum(unsigned char*)icmph, length); 函数的返回值为-1 时表示褚翠,其他值则正常。 /* 解压接收到的包,并打印信息*/ static int icmp_unpack(char *buf,int len) in
15、t i,iphdrlen; struct ip *ip = NULL; struct icmp *icmp = NULL; int rtt; ip=(struct ip *)buf; /* IP 头部*/ iphdrlen=ip-ip_hl*4; /* IP 头部长度*/ icmp=(struct icmp *)(buf+iphdrlen); /* ICMP 段的地址*/ len-=iphdrlen; if( lenicmp_type=ICMP_ECHOREPLY) /* 在发送表格中查找已经发送的包,按照seq */ pingm_pakcet* packet = icmp_findpacke
16、t(icmp-icmp_seq); if(packet = NULL) return -1; packet-flag = 0; /* 取消标志*/ tv_send = packet-tv_begin; /* 获取本包的发送时间*/ gettimeofday( /* 读取此时时间,计算时间差*/ tv_internel = icmp_tvsub(tv_recv,tv_send); rtt = tv_internel.tv_sec*1000+tv_internel.tv_usec/1000; /* 打印结果,包含 * ICMP 段长度源 IP 地址包的序列号TTL 时间差 */ printf(“%
17、d byte from %s: icmp_seq=%u ttl=%d rtt=%d msn“, len, inet_ntoa(ip-ip_src), icmp-icmp_seq, ip-ip_ttl, ,rtt ); packet_recv +;/* 接收包数量加1 */ else return -1; 计算时间差 由于需要评估网络状况,在发送数据报文的时候保存发送时间,接收到报文后, 计算两 个时刻之间的差值,生成了ICMP 源主机和目标主机之间的网络状况的时间评估。 发送报文 发送报文函数是一个线程,每隔1s 向目的主机发送一个ICMP 回显请求报文,它在整 个程序处于激活状态(alive
18、 为 1)是一直发送报文。 (1)获得当前的时间值, 按照序列号packet_send将 ICMP 报文打包到缓冲区send_buff 中后,发送到目的地址。发送成功后,记录发送报文的状态: 序号 seq 为 packet_send。 标志 flag 为 1,表示已经发送但是没有收到响应。 发送时间为之前获得的时间。 (2)每次发送成功后序号值会增加1,即 packet_send+. (3)在线程开始进入主循环while(alive) 之前,将整个程序的开始发送时间记录下来, /*计算时间差time_sub 参数: end,接收到的时间 begin,开始发送的时间 返回值: 使用的时间 */
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ping 命令 设计 实现 要点
链接地址:https://www.31doc.com/p-5197804.html