网络命令ping、netstat、pidof
ICMP协议(Internet Control Message Protocol)
ICMP协议是一个网络层协议,和IP协议是一层的,该协议不用来进行数据传输,而是用来进行进行网络诊断。不保证可靠传输(没有超时重传、确认应答机制),无连接可直接发报文,该协议是基于IP协议之上工作的
ICMP 的报文格式
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type(8) | Code(8) | Checksum(16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data(可变长度) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
一行4字节
重要字段:
-
Type(类型):8位,表示ICMP报文的类型。对于Echo Request(回送请求)类型为8;Echo Reply(回送应答)类型为0。
-
Code(代码):8位,用于进一步区分某种类型中的不同情况。对于Echo Request和Echo Reply,Code都为0。
-
Checksum(校验和):16位,用于检查ICMP报文在传输过程中是否出错。计算校验和时,将ICMP报文(包括头部和数据)以16位为单位进行累加,然后取反,这样后面校验时只需累加头部和数据看看最终结果是不是零即可。
-
Identifier(标识符):16位,用于找到对应原始套接字。通常,发送方会设置一个标识符,接收方在应答中返回相同的标识符。ping命令中,这个字段通常设置为进程ID。
-
Sequence Number(序列号):16位,用于标识报文的顺序。每发送一个Echo Request,序列号就会递增。接收方在Echo Reply中返回相同的序列号。
-
Data(数据):可变长度,是报文的载荷。在Echo Request中,发送方可以选择填充任意数据,接收方在Echo Reply中返回相同的数据。ping命令中,通常包含发送请求的时间戳。
ping 命令
ping(Packet Internet Groper)是一个基于 ICMP(Internet Control Message Protocol)协议 的命令,用于测试主机之间网络连通、延迟和丢包情况。它的核心原理是发送 ICMP Echo Request 回送请求并等待 ICMP Echo Reply回送响应 ,其中ping进程通过原始套接字和协议栈来发送请求和处理响应,利用ICMP 响应报文来得到路由情况,目标主机通过协议栈来处理请求并进行响应
ping命令过程详解
在终端中输入ping www.baidu.com,然后终端模拟器获取到键盘输入后将字符串write写进主设备,终端驱动将数据从主设备写进从设备,shell从标准输入也就是从设备中读出字符串,然后分割成命令行参数用char*数组argv来保存,使用fork创建子进程,子进程设为新进程组,并设置为前台进程组,然后用execve,传参argv和environ,子进程被替换成ping进程,ping进程会向DNS服务器发送DNS查询报文,DNS服务器和各级服务器进行交互,最终收到了域名对应的ip地址,然后将ip地址以DNS响应报文返回给ping进程主机,ping进程会创建原始套接字socket(AF_INET, SOCK_RAW, IPPROTOCOL_ICMP),流式、数据报式套接字使用元组来标识套接字文件, 该原始套接字的标识就是ping进程的pid,然后ping进程组装ICMP回送请求报文,类型填8,标识符identifier填进程pid,递增序号从1开始,数据里要加时间戳,使用sendto接口进行发送,这里sendto里填的参数其实只需要目的ip,端口是无效的,走协议栈,经ip协议和以太网协议网卡后将mac帧发出,接下来ping进程调recvmsg读取原始套接字接收缓冲区阻塞等待,等到目标主机网卡收到mac帧后,写进网卡对应接收缓冲区,触发硬件中断,后面中断处理调用网卡驱动,从网卡接收缓冲区根据IP报头中的ip报文总长度读出mac帧,然后去头去尾交给ip层,IP层一看MF和片偏移都是0,那也不分片,于是去头然后交给ICMP层,ICMP报文类型是8 回送请求,所以组装类型为0的回送应答ICMP报文,标识符pid、序号1都不变,有效载荷中的时间戳也不变,交给ip层封装IP报头,TTL又为64了,经数据链路层处理后又被发出,ping进程主机网卡收到响应后,同样网卡的DMA引擎将mac帧写进网卡对应接收缓冲区,然后网卡触发硬件中断,中断处理函数会先读出mac帧然后走协议栈,数据链路层去掉mac头和CRC校验码后分用交给ip层,ip层会将响应报文的ip头中的TTL、源IP地址、ICMP报文一并交给ICMP层,然后ICMP层将TTL、ip地址封装成辅助数据加到ICMP报文的有效载荷中,通过pid找到原始套接字,将ICMP报文 写进原始套接字接收缓冲区里面,唤醒接收缓冲区等待队列上的ping进程,recvmsg返回数据到应用层,ping进程根据ICMP报文,足以组建出如以下的字符串
64 bytes from 93.184.216.34: icmp_seq=1 ttl=53 time=11.3 ms
其中TTL就是目的主机到ping进程主机所剩余的跳数,IP层报头里的TTL从64减为了53,序号的话ICMP报头里有,从ICMP响应报文有效载荷中读出发送请求时的时间戳,再和接收到响应报文的时间戳做减法,最后得到往来时间,ping进程将字符串write写进标准输出也就是从设备,然后终端驱动将从设备数据写进主设备,终端模拟器读出后显示出来

补充说明
1.ping 超时:内核1s后未收到 Echo Reply,recvmsg() 停止等待,往标准输出里写没有收到响应的提示消息,然后进程靠循环和sendto重发ICMP报文回送请求,也就是说ICMP协议是没有超时重传的功能的,真正能使其超时重传的是ping进程逻辑
2.ping发送请求到目标主机,目标主机通过硬件中断和协议栈函数就处理了该请求,根本就没涉及套接字,但是ping进程一方必须有套接字帮助,只有硬件中断不行
netstat
netstat 是一个用来查看网络状态的重要工具.
-t(tcp):显示 TCP 连接
-u(udp):显示 UDP 连接
-a(all):netstat默认只显示活跃连接,加-a将其他监听端口但不活跃的连接也显示出来
-n:显示信息中不显示别名,能显示数字的全部转化成数字
-p:显示连接对应的进程的pid

pidof命令
pidof命令会打印对应的进程的pid

