域名介绍
在网络通信中,需要用到ip加port,但是ip并不方便记忆,于是我们常用域名来对应一个ip
例如:www.baidu.com 对应 156.36.56.98(随便写的)
com: 一级域名. 表示这是一个企业域名. 同级的还有 "net"(网络提供商), "org"(非盈利组织) 等.
baidu: 二级域名, 公司名.
www: 只是一种习惯用法.
域名解析
域名解析分为两步
1.查本地 /etc/hosts
互连网信息中心(SRI-NIC)会管理一个 hosts 文件,本地主机只需要定期下载即可,里面就是域名和ip的对应
2.使用DNS技术
如果/etc/hosts找不到,那就去向本地DNS服务器发送请求进行查询,本地DNS服务器通常以守护进程形式存在
ICMP协议
ICMP 的报文格式
标准 ICMP Echo Reply 报文格式
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type(0) | Code(0) | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data (可变长度,通常包含时间戳或填充字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ping 命令
ping www.baidu.com
ping命令过程分析:
在终端上写下了这几个字母,随着按下回车,终端模拟器将这几个字母write进主设备,然后驱动程序将主设备数据写进从设备,唤醒从设备等待队列上的进程也就是shell,然后shell读出来,分割字符串,然后创建子进程,进程替换为ping进程,域名通过命令行参数传给了ping进程,然后ping进程去/etc/hosts文件里面查找域名对应ip,如果找不到就向本地DNS守护进程发消息,然后DNS进程开始询问服务器,最后得到对应ip。ping进程接下来的操作如下:
步骤 1:创建原始套接字
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock < 0) {perror("socket"); // 需 root 权限或 CAP_NET_RAW 能力exit(1);
}
步骤 2:构造 ICMP 报文
- 报文结构:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type(8) | Code(0) | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Payload (可选) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 字段说明:
- Type=8, Code=0:表示
Echo Request
。 - Identifier:通常为进程 PID(用于响应能够查找到对应套接字)。
- Sequence Number:递增序列号(区分多次请求)。
- Checksum:ICMP 校验和(需手动计算)。
- Type=8, Code=0:表示
步骤 3:发送报文
struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr("93.184.216.34"); // 目标 IP// 发送 ICMP 报文
sendto(sock, icmp_packet, sizeof(icmp_packet), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
步骤 4:接收 Echo Reply
char recv_buf[1024];
struct sockaddr_in src_addr;
socklen_t addr_len = sizeof(src_addr);// 阻塞等待响应(内核通过 Identifier 匹配报文)
recvfrom(sock, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&src_addr, &addr_len);
ping进程在应用层创建好原始套接字,并且创建好ICMP报文,然后用sendto发送,然后经过ip层和数据链路层封装后发出去,当目标主机收到后,经数据链路层和ip层的解包,交给了ICMP协议的接口,检查ICMP头里的类型,发现是请求,那就构建对应的ICMP响应,然后经IP协议和以太网协议的封装又发回去,源主机收到后开始解包,到ICMP协议层时,根据OS维护的hash表,通过响应里的identifier标识符,找到对应的套接字,然后将ICMP报文写进套接字接收缓冲区,并唤醒等待队列上的进程,ping进程recvfrom从接收缓冲区里读出来完整的ICMP报文,然后根据ICMP报文的内容,write写东西到从设备,终端驱动将从设备数据拷到主设备,然后唤醒终端模拟器,终端模拟器再将东西打到终端上,这就是一次发送数据测试,ping进程会不停发送echo request,并设置序列号来区分这些请求3
完整流程:ping
命令的 ICMP 请求与响应全链路解析
1. ping
进程发送 ICMP Echo Request
(1)应用层(用户态)
创建原始套接字
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- 权限:需有
CAP_NET_RAW
(/bin/ping
已默认配置)。 - 作用:绕过传输层,直接操作网络层(IP)数据包。
- 权限:需有
构造 ICMP Echo Request
- 报文结构:
Type=8 (Echo Request), Code=0
Identifier=进程PID, Sequence=递增序号
Payload=时间戳或填充数据
- 计算校验和:覆盖整个 ICMP 报文。
- 报文结构:
发送请求
sendto(sock, icmp_req, sizeof(icmp_req), 0, &dest_addr, addr_len);
(2)内核协议栈处理
IP 层封装
- 添加 IP 头部:
- 源/目标 IP、TTL(默认 64)、协议号
1
(ICMP)。
- 源/目标 IP、TTL(默认 64)、协议号
- 查询路由表,确定下一跳 ip 地址和发送接口。
- 添加 IP 头部:
数据链路层封装
- 添加以太网帧头:源/目标 MAC 地址、类型
0x0800
(IPv4)。 - 通过网卡驱动(如
eth0
)发送到物理链路。
- 添加以太网帧头:源/目标 MAC 地址、类型
2. 目标主机处理与响应
(1)网络接口接收
网卡(数据链路层)
- 检查目标 MAC 地址,若匹配则接收,剥离以太网帧头。
- 将 IP 数据包交给内核网络协议栈。
IP 层解包
- 校验 IP 头部(版本、校验和、目标 IP)。
- 若 TTL 减至 0,丢弃并返回
ICMP Time Exceeded
(Type=11)。 - 若目标 IP 匹配本机,剥离 IP 头,根据协议类型是
1,
交给 ICMP 模块。
(2)ICMP 协议处理
解析 ICMP 报文
- 检查
Type=8
(Echo Request),Code=0
。 - 内核自动构造
Echo Reply
(Type=0),保持相同的Identifier
和Sequence
。
- 检查
发送响应
- IP 层封装:源/目标 IP 互换,TTL 重置(如 64)。
- 数据链路层封装:通过 ARP 获取源主机的 MAC 地址。
- 网卡发送响应包。
3. 源主机接收响应
(1)网络接口接收
网卡收包
- 过滤目标 MAC,剥离以太网帧头,IP 层校验后交给 ICMP 模块。
ICMP 协议匹配
- 内核根据
Identifier
(如 PID1234
)查找原始套接字。 - 将报文写入套接字接收缓冲区。
- 内核根据
(2)唤醒 ping
进程
从阻塞中恢复
ping
进程此前因recvfrom()
阻塞,被内核移至就绪队列。- 从接收缓冲区读取
Echo Reply
数据。
计算 RTT(往返时间)
- 对比当前时间与请求报文中的时间戳(Payload),得到延迟。
(3)终端输出
ping
进程格式化输出64 bytes from 93.184.216.34: icmp_seq=1 ttl=53 time=11.3 ms
ttl
:从响应 IP 头部提取。time
:RTT 计算结果。
终端显示流程
ping
调用write()
将结果写入标准输出(文件描述符1
)。- 终端驱动(如
tty
)将数据从 从设备(进程缓冲区)拷贝到 主设备(终端显示器)。 - 终端模拟器(如
xterm
)渲染最终字符。
补充说明
1.ping
超时:内核未收到 Echo Reply
,recvfrom()
超时后停止等待(等待默认 1 秒),靠sendto重发请求,也就是说ICMP协议是没有超时重传的功能的,真正能使其超时重传的是ping进程逻辑
2.ping发送请求到目标主机,目标主机通过硬件中断的协议栈就处理了该请求,根本就没涉及到进程和应用层逻辑
3.ping进程本身处理响应却是寄托协议栈加上进程和应用层逻辑,还使用了套接字