请结合附件:Ping的实现原理与ping.cpp的内容,编写一个程序,使其能够实现简单的ping的功能,即判断目标网站是否可以连接,然后通过Wireshark进行抓包分析其ICMP协议,指出哪个数据包是ping的请求(request),哪个数据包是对这个请求的回应(reply)(如果reply数据包存在的话)。
相关知识:
ICMP (Internet Control Message Protocol) Internet控制报文协议,它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息(即提供TCP/IP网络上设备、服务协议及路由器可用性的信息),ICMP允许主机或路由器报告差错情况和提供有关异常情况的报告,目的是为了更有效地转发IP数据报和提高交付成功的机会。 注:控制消息指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。 ICMP的两个主要应用是Ping和Traceroute。 需要编写程序,实现简单的ping的功能,主要需要了解以下内容: 要点1:ICMP协议相关知识 ICMP不是高层协议,而是IP层的协议。ICMP报文是装在IP数据报中,作为其中的数据部分。 ①ICMP报文的格式 ★ICMP协议的类型码与代码根据不同情况,各自取值。8bits类型和8bits代码字段:一起决定了ICMP报文的类型,常见的有: A.类型8、代码0:回射请求。 B.类型0、代码0:回射应答。 C.类型11、代码0:超时。 ★ICMP报文的前4个字节是统一的格式,共有三个字段:即类型、代码和检验和。接着的4个字节的内容与ICMP的类型有关。(这8个字节为ICMP报文的首部) ②ICMP报文的种类 从类型值来看ICMP报文可分为二大类: A.差错报告报文;
B.询问报文。
要点2:IP地址的点分十进制表示 机器中存放的IP地址是32位二进制代码。以8位为一组,采用点分十进制记法可以进一步提高可读性,如图所示: 在实验代码中,使用到的两个函数inet_addr()和Inet_ntoa()完成的就是32位二进制表示的IP地址与点分十进制记法之间的转换: ①inet_addr函数(点分十进制->32位二进制)需要一个字符串作为其参数,该字符串指定了以点分十进制格式表示的IP地址(例如:192.168.0.16)。而且inet_addr函数会返回一个适合分配给S_addr的u_long类型的数值。 ②Inet_ntoa函数(32位二进制->点分十进制)会完成相反的转换,它接受一个in_addr结构体类型的参数并返回一个以点分十进制格式表示的IP地址字符串 注:在vs2013以上的版本会出现这个两个无法使用的错误信息及相对应的解决方法如图所示: 这两个函数是随IPv6出现的新函数,对于IPv4地址和IPv6地址都适用。对比与使用方法可参见:https://blog.csdn.net/gujintong1110/article/details/45390653 要点3:校验和的计算(具体实现可参见参考代码ping.cpp) 在发送数据时,为了计算数据包的检验和。应该按如下步骤: 1.把校验和字段设置为0; 2.把需要校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和; 3.把得到的结果存入校验和字段中 在接收数据时,计算数据包的检验和相对简单,按如下步骤: 1.把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段; 2.检查计算出的校验和的结果是否为0; 3.如果等于0,说明被整除,校验和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。 注:IP、ICMP、UDP和TCP报文头都有检验和字段,大小都是16bit这四种报文的校验和算法一样,但是在作用范围存在不同: IP校验和只校验20字节的IP报头; |