1. IP 协议
1.1 认识 IP 协议
主机B要向主机C发送数据,报文所经历的流程:

一些基本概念:
- 主机:配有IP地址,也要进行路由控制的设备
- 路由器:既配有IP地址,又能进行路由控制
- 节点:主机和路由器的统称
后续表述中,两端主机叫做主机,路上节点叫做节点。主机B发送的报文到主机C,经历每一跳到达主机C,实际上是多个子网的级联。因此跨网络通信就是把多个局域网进行串联的过程。
报文要从主机B到达主机C,首先得到达主机B所在的出入口路由器,先要出门,门都出不了,怎么到达主机C?整个报文的传输过程是一跳一跳的。主机B能够跳转到路由器F,就证明了主机B和路由器F在同一个子网(局域网)。报文从主机B送到主机C的本质,是要经历多个子网的转发。
为什么报文要从主机B到达主机C,需要走上面那条路径?为什么不走别的?主机是根据报文中的目的IP,进行路径选择的。IP地址 = 目标网络 + 目标主机。IP具有一定的指向性。互联网中的任意一台主机都属于某个子网,要到达某个主机,首先要到达它所在的子网。
IP协议主要解决网络通信过程中,将数据报从主机A跨网络经过路径选择、路由转发,送到主机B。IP协议有这种能力,能力指的是极大的概率做成某种事情。IP协议有极大的概率将数据报从主机A跨网络送到主机B。但是网络不要极大概率,要保证可靠。既然IP协议自己做不到可靠,就需要提供相应的策略,使之能够做到。
TCP + IP 提供了数据报从主机A跨网络经过路径选择、路由转发,可靠地送到主机B。可靠由TCP提供,传输由IP提供。TCP/IP协议提供了网络所需要的基本功能。
1.2 IP 协议报头
IP 协议报头格式:

这里的数据就是上一层UDP/TCP交付给IP的。
任何协议需要解决的两个问题:
- IP报头和有效载荷分离的问题
IP报头的标准长度是20字节,和TCP报头的标准长度一样。在20字节报头中,存在一个4位首部长度 字段,功能与TCP协议一致,取值范围[0, 15],单位为4字节。根据4位首部长度就可以确认报头有多长。此外,还存在16位总长度字段,它标明整个IP报文(报头+有效载荷)的总长度。有了这两个字段,就能将报头和有效载荷分离。 - 有效载荷分用问题
在IP报头中存在8位协议 字段,记录数据是UDP还是TCP。此外还有32位目的IP地址来找到目标主机。
这个8位协议字段谁来填?发送端来填,它当然知道有效载荷是谁交付给它的。
4位版本:指定IP协议的版本,IPv4就是4,IPv6就是6。
8位服务类型(TOS):3位优先权字段(已弃用),4位TOS字段,1位保留字段(必须置0)。4位TOS分别表示:最小延时、最大吞吐量、最高可靠性、最小成本。四者相互冲突,只能选一个。
8位生存时间(TTL):数据报到达目的地的最大报文跳数,常见初始值64。每经过一个路由器,TTL减1,减到0还没到达就丢弃。主要用来防止路由循环。
为什么数据报经过路由器TTL会减,但光电信号不衰减?物理层的中继设备(如集线器、交换机)会重新生成信号,但TTL是网络层的逻辑跳数计数器,两者不冲突。
1.3 IP分片与组装
在学习TCP滑动窗口时,有个问题:滑动窗口内的内容可以直接发送给对方,暂时不需要收到应答。如果对方接收能力为4000字节,为什么不直接发送一个4000字节的报文,而要分成多个小段?因为IP报文过长会分片。
数据链路层协议规定,有效载荷长度不能超过MTU ,一般以太网MTU=1500字节。数据链路层的上一层是IP层,因此IP层交给数据链路层的报文不能超过1500字节。如果超过了,需要将报文拆分成若干片。
数据链路层只定要求,不做拆分,如果不拆分,就直接丢弃。
谁来拆?网络层(IP层)拆分 ,组装由对端网络层 完成。
从网络通信角度,不建议报文做过多分片和组装,因为:
- 效率低
- 分片越多,丢失概率上升,丢失一片就导致整个报文重传(上层TCP会重传整个报文)
网络层是否分片,不由它自己决定,而是由上层传输层决定 。因此为了减少分片,TCP在滑动窗口中将数据分成一个个MSS大小的段。
虽然TCP尽量规避分片,但分片仍然可能发生,比如中间设备的MTU比发送端小。
计算题 :TCP和IP都采用标准报头(各20字节),数据链路层MTU=1500字节。
传输层给网络层的数据最大为:1500 - 20(IP头) - 20(TCP头)= 1460 字节(即MSS)。
双方怎么知道对方传输层的MSS?双方在TCP三次握手时就已经交换了MSS。
以组装作为切入点,理解分片和组装,理解了怎么组装,自然也就知道了怎么分片。
首先需要识别出来哪些报文分片了,哪些报头没有分片。怎么识别?IP报文分片并不是,将一个报文直接咔嚓分片,每个分片都要携带IP报头。怎么知道报文没有被分片?MF = 0 && 片偏移 = 0 。那么反向思考,报文分片了,则****MF != 0 && 片偏移 != 0。也可以**区分出分片的头和尾,头部分MF!=0,**尾部分片偏移!=0。
如何知道报文被分成了多少片?通过16位标识来聚合,同一个原始报文的所有分片具有相同的标识。
如何保证收全了?把所有分片按片偏移升序排序,检查:
- 首片偏移为0
- 尾片MF=0
- 中间连续:当前分片的偏移 + 当前分片的数据长度 = 下一个分片的偏移
3位标志中,第一位保留 ,第二位(DF) 为1表示禁止分片,如果报文超过MTU则丢弃,**第三位(MF)**表示更多分片。
13 位片偏移 :表示当前分片相对于原始报文起始位置的偏移量,单位是8字节 。
因此,实际偏移字节数 = 片偏移值 × 8。
这要求除最后一个分片外,其他分片的有效载荷长度必须是8的整数倍。
例子:假设IP层有一个大小为3000字节的报文(含20字节IP头),MTU=1500。
- 有效载荷 = 3000 - 20 = 2980字节
- 第一片:IP头20字节,有效载荷1480字节(1500-20),MF=1,片偏移=0,剩余载荷1500字节
- 第二片:IP头20字节,有效载荷1480字节,MF=1,片偏移=1480/8=185,剩余载荷20字节
- 第三片:IP头20字节,有效载荷20字节,MF=0,片偏移=(1480+1480)/8=370
注意:第三片有效载荷20字节不是8的倍数,但它是最后一片,允许不满8字节。
分片的底层管理
在 Linux 内核(以及大多数现代操作系统)中,为了唯一确定一个分片队列,必须使用一个四元组来作为"指纹"。
当网卡收到一个分片包时,内核会创建一个 sk_buff 结构体。为了找到它属于哪个"大家族"(即哪个原始数据包),内核会提取以下信息构建索引:
| 关键字段 | 作用 | 备注 |
|---|---|---|
| 源 IP 地址 | 标识发送者 | 防止不同主机发送的相同 ID 包混淆 |
| 目的 IP 地址 | 标识接收者 | 确保包是发给本机的 |
| 协议号 | 标识上层协议 | 如 TCP(6) 或 UDP(17),不同协议的分片不能混在一起 |
| 16位标识符 | 核心分组依据 | 同一个大包切出来的所有分片,这个值必须相同 |
操作系统通常会维护一个哈希表(Hash Table)或链表。
- 入队: 当第一个分片到达时,内核创建一个新的重组队列。
- 归位: 后续到达的分片,根据上述四元组找到对应的队列,并根据片偏移插入到链表的正确位置(保持有序)。
查找是否有分片丢失的逻辑:
- 首片检测(起始位置):必须存在一个 Offset = 0 的分片。如果队列里第一个分片的偏移量不是 0,说明首片丢了。
- 尾片检测(结束位置):必须存在一个 MF (More Fragments) = 0 的分片。如果一直没收到 MF=0 的包,说明尾部还没到,或者尾片丢了。
- 中间连续性检测(最关键的"拼图"):
- 内核会遍历链表中的 sk_buff。
- 计算公式:当前分片的结束位置 = 当前分片的偏移 + 当前分片的数据长度。
- 判断标准: 当前分片的结束位置,必须严格等于下一个分片的起始偏移。
- 例子:分片 A:偏移 0,长度 1480。预期下一个偏移是 1480。分片 B:偏移 1480,长度 1480。预期下一个偏移是 2960。分片 C:偏移 3000... -> 警报! 2960 到 3000 之间有 40 字节的数据丢失(或者分片 C 的偏移计算有误)。
向上交付的过程:
只有当上述的"拼图"完美闭合(有头、有尾、中间无缝隙)时,内核才会将这些零散的 sk_buff 合并(或者构建一个新的 sk_buff 指向这些数据),剥离 IP 头部,将完整的 Payload 交给上层协议(TCP/UDP)。
超时机制:如果中间有分片丢失(比如分片 B 丢了),队列就会一直处于"等待"状态。为了防止内存泄漏,操作系统会启动一个定时器(Linux 中通常默认是 30 秒左右)。一旦超时,只要拼图还没拼完整,内核会无情地丢弃该队列中所有已收到的分片。对于上层 TCP 来说,这就相当于整个大包丢了,从而触发 TCP 的超时重传机制。
为什么片偏移只有13位,却能表示16位总长度的范围?
16位总长度最大为65535字节,13位片偏移最多表示8192个单元。协议设计巧思 :片偏移的单位是8字节,因此最大可表示 8192 × 8 = 65536 字节,刚好覆盖IP报文最大长度。
这是一种约定,发送和接收双方网络层都遵守:
- 分片时:片偏移值 = 实际偏移字节数 / 8(低3位必须为0,即8字节对齐)
- 组装时:实际偏移字节数 = 片偏移值 × 8
这和页表中用20位表示32位物理地址(因为低12位为0)是同一个思想。
这也回答了之前的问题,为什么有效载荷长度要拉满至1480,这样刚好能够整除8。
问题来了:之前在表示分片的举例中,最后一个分片的有效载荷的长度只有20,并不是8的整数倍呀?会自动填充至8的整数倍。
ip 报头中总长度16位,片偏移13位,为了完整的表示16位总长度,会左移8字节来表示。但是为什么不将16位标识字段,变成13位标识字段,多出来的3位给片偏移使用?
IP 协议之所以没有把 16 位标识符压缩成 13 位来给片偏移使用,是因为标识符和片偏移解决的是完全不同的问题,且标识符的"唯一性"需求比片偏移的"范围"需求更紧迫。
标识符(ID)的"身份证号"作用不可替代。16 位标识符的作用是给数据包打上"批次号"。
为什么要 16 位?
在网络通信中,主机发送数据的速度非常快。标识符必须保证在短时间内发送的每一个数据包(无论是分片还是不分片)都有唯一的编号。如果压缩成 13 位会怎样?
13 位只有 8192 个编号,而 16 位有 65536 个。如果只有 13 位,在高吞吐量的网络环境下(比如现在的千兆、万兆网络),编号会迅速用尽并开始回绕。编号回绕会产生什么后果?
假设你刚发了一个 ID 为 100 的包,还没到达目的地,因为编号不够用,你又发了一个新的包,ID 也是 100。接收端就会发疯:"这到底是旧包的分片,还是新包的分片?" 这会导致数据重组混乱。
因此:16 位是为了防止在高并发下 ID 冲突,它保护的是"身份的唯一性"。
之所以不"拆东墙补西墙"(把标识符的位给片偏移),是因为:
- 片偏移已经通过"以 8 字节为单位"的技巧,完美覆盖了 IP 包的最大长度限制,不需要更多位数了。
- 标识符如果减少 3 位,会大大增加数据包 ID 冲突的风险,导致网络重组错误,这个代价是无法接受的。
所以,IP 协议的设计者选择保留 16 位标识符来确保身份安全 ,而通过强制8字节对齐 的规则来让 13 位片偏移刚好够用。
1.4 总结
IP协议负责尽力而为 地将数据报从源主机送到目的主机,TCP协议负责可靠性 。
IP分片是为了适应数据链路层MTU限制,但应尽量避免,因为分片降低效率、增加失败概率。
分片和组装的核心是16位标识 、MF标志 和片偏移 ,操作系统通过四元组管理分片队列,超时未收全则丢弃。
片偏移的13位通过以8字节为单位,巧妙覆盖了IP报文的最大长度范围,而16位标识符的保留保证了高并发下的正确重组。
2. 网段划分
IP地址分为两个部分:网络号 和主机号
- 网络号:保证相互连接的不同网段具有不同的标识
- 主机号:同一网段内,主机之间具有相同的网络号,但必须有不同的主机号

路由器有一个核心能力:构建子网(局域网)。
不同的子网,其实就是把网络号相同的主机放到一起。如果在子网中新增一台主机,那么这台主机的网络号必须和这个子网的网络号一致,主机号不能和子网中的其他主机重复。
- 在同一个子网内,主机的网络号一定相同,主机号一定不同
- 在不同的子网内,主机的主机号可能相同,但主机的网络号一定不同
通过合理设置主机号和网络号,就可以保证在相互连接的网络中,每台主机的IP地址都不相同。手动管理子网内的IP是一件相当麻烦的事情。有一种技术叫做DHCP,能够自动给子网内新增的主机节点分配IP地址,避免了手动管理IP的不便。一般的路由器都带有DHCP功能,因此路由器也可以看做一台DHCP服务器。
IP地址分成网络地址和主机地址,为什么要进行网段划分?
把报文交给目标主机的本质是一个查找工作,从多台主机中找到目标主机。查找的本质是淘汰 。淘汰的效率越高,查找的效率就越高。
所以为什么要进行网段划分?为了支持在查找目标网络的过程中快速淘汰,大大提高查找目标主机的效率。
如何进行网段划分?IP地址是有限的,并且需要被有效利用。
过去曾经提出一种划分网络号和主机号的方案,把所有IP地址分为五类,如下图所示:

- A类:0.0.0.0 ~ 127.255.255.255(首位0,7位网络号,24位主机号)
- B类:128.0.0.0 ~ 191.255.255.255(前两位10,14位网络号,16位主机号)
- C类:192.0.0.0 ~ 223.255.255.255(前三位110,21位网络号,8位主机号)
- D类:224.0.0.0 ~ 239.255.255.255(前四位1110,用于多播)
- E类:240.0.0.0 ~ 247.255.255.255(前五位11110,留待后用)
随着互联网的发展,这种分类划分方案的局限性很快显现出来。大多数组织都申请B类网络地址,导致B类地址很快就分配完了,而A类却浪费了大量地址。
例如,申请了一个B类地址,理论上一个子网内能允许6万5千多个主机。A类地址的子网内主机数更多。然而实际网络架设中,不会存在一个子网内有这么多主机的情况,因此大量的IP地址都被浪费掉了。
分类划分法最大的问题:IP地址使用不充分。
针对这种情况,提出了新的划分方案,称为CIDR(无类别域间路由)。
引入一个额外的子网掩码来区分网络号和主机号。子网掩码也是一个32位的正整数,通常用一串连续的"1"开头,后面跟连续的"0"。将IP地址和子网掩码进行按位与操作,得到的结果就是网络号。网络号和主机号的划分与这个IP地址是A类、B类还是C类无关。
子网掩码被设置到路由器内 。子网掩码的左半部分由1构成,右半部分由0构成,1和0必须是连续的。例如:11111111 11111111 11111111 00000000(即255.255.255.0)。
假设路由器所在子网的IP地址为192.168.128.1,子网掩码为255.255.255.0,将IP地址与子网掩码按位与,将低位清0,得到网络号192.168.128.0。
之后,通过调整子网掩码中1和0的比例,就可以实现灵活的网段划分。
假设我申请了一个A类网络(网络号占8位,主机号占24位)。虽然理论上这个子网内可以有1600多万台主机,但我实际只使用了低16位作为主机号,那么就会多出来8位。这8位可以在子网内继续划分更小的子网(即子网划分),形成内网嵌套。往后就不需要再死板地遵循分类划分法了,CIDR完全支持这种灵活的划分方式。
两个划分子网的例子:


CIDR在一定程度上缓解了IP地址不够用的问题(提高了利用率,减少了浪费),但是IP地址的绝对上限并没有增加,仍然不是很够用。这时候有三种主要方式来解决:
- 动态分配IP地址(DHCP):只给接入网络的设备分配IP地址。因此同一个MAC地址的设备,每次接入互联网中,得到的IP地址不一定是相同的。这提高了IP地址的复用率,但并没有增加可用IP的总数。
- IPv6:IPv6并不是IPv4的简单升级版,这是两个互不相干的协议,彼此并不兼容。IPv6用16字节(128位)来表示一个IP地址,地址空间极大。但目前IPv6在公网内还没有完全普及。
- NAT技术:这是当前最主要的解决方案。通过NAT(网络地址转换),多个私有IP地址可以共享同一个公网IP地址访问互联网,极大地缓解了IPv4地址枯竭的压力。
3. IP 地址
特殊IP地址
- 网络号:将IP地址中的主机地址全部设为0,就成为了网络号,代表这个局域网
- 广播地址:将IP地址中的主机地址全部设为1,就成为了广播地址,用于给同一个链路中相互连接的所有主机发送数据包
- 环回地址:127.* 的IP地址用于本机环回(loopback)测试,通常是127.0.0.1。发往该地址的数据不会离开本机
IP分为公网IP 和私有IP 两大类。如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到互联网上,理论上使用任意的IP地址都可以。但是RFC1918规定了用于组建局域网的私有IP地址范围:
- 10.*:前8位是网络号,共16,777,216个地址
- 172.16. ~ 172.31.**:前12位是网络号,共1,048,576个地址
- 192.168.*:前16位是网络号,共65,536个地址
包含在这个范围中的都称为私有IP ,其余的则称为全局IP(或公网IP)。
- 公网IP地址:标识全网唯一的一台主机
- 私有IP地址:用于组建内网,谁来组建内网?路由器或者类似路由器的设备
4. 认识运营商
在每月交付话费时,为什么是交给运营商?假设要访问CSDN网站,数据不是一下就到CSDN了,中间需要做很多的基础工作,这些基础工作都是运营商完成的。
我们都知道互联网中存在墙,那么墙在哪里?在运营商处 。为了能够访问墙外网站,需要科学上网。科学上网的本质就是在骗运营商,让运营商认为我的报文是合法报文。
运营商的经营有很强的地域性。
上网的流程图:

一个路由器可以配置两个IP地址:一个是WAN口IP(连接广域网),一个是LAN口IP(子网IP,即网关地址)。路由器LAN口连接的主机,都从属于当前这个路由器的子网中。
我们所有人,都不可能直接连接公网,我们都是先连接到局域网中,通过局域网接入公网。因此组建局域网只能使用特定的私有IP。为什么私有IP有那么多种?就是为了满足各种场景。
私有IP可以重复!但是公网IP不能重复。 因为私有IP可以重复,因此IP不足的问题就大大被缓解了。
主机A要向主机C(公网服务器)发送数据的流程:
- 主机A发出的报文:源IP:192.168.1.201(私有);目标IP:122.77.241.3(公网)
- 主机A判断目标主机一定不在本局域网内(将自己的IP与子网掩码按位与,得到本子网网络号192.168.1.0,目标IP显然不在此范围),于是将报文交给家用路由器。
- 家用路由器(NAT转换) :
- 查看目标IP 122.77.241.3,不是本局域网内的
- 将报文的源IP地址 从 192.168.1.201 替换为家用路由器的WAN 口IP(例如10.1.1.2)
- 同时记录这个映射关系(NAT表)
- 将报文转发给运营商路由器
- 运营商路由器 :
- 同样可能再做一层NAT(取决于运营商),将其WAN口IP(如122.77.241.4)替换为新的源IP
- 最终报文进入公网时,源IP已经是一个公网IP(如122.77.241.4)
- 公网上的路由器根据目标IP 122.77.241.3,将报文转发给目标服务器。
每次经过一个内网到公网方向 的路由器,都可能替换源IP地址,变成当前设备的WAN口IP。进入公网后,就不再替换了。这个替换动作主要发生在内网出口路由器 上。这种源IP地址替换技术,称之为NAT(网络地址转换)。
现在报文能从内网传到公网了,但是到达目的地后,怎么源路径返回?在后续详细讲解NAT时,再做回答。
为什么要这么费劲地转换来转换去?核心就是为了支持内网IP复用 ,让私有IP可以重复,极大地缓解了IP地址不足的问题。我们大多数人都在局域网中,不消耗公网IP,真正消耗公网IP较多的在广域网侧(运营商、数据中心、服务器等)。
如果希望我们自己实现的服务器程序,能够在公网上被访问到,就需要把程序部署在一台具有公网IP的服务器上。这样的服务器可以在阿里云/腾讯云上进行购买。云服务器分配给你的就是一个公网IP(或者通过弹性公网IP绑定)。
5. 理解公网
在学校中,能够通过学号找到某名同学,不仅仅因为学号设置成了特定的格式,能够让你通过解析学号来定位某名同学。产生学号只是结果,最重要的原因是在学校办学之初,就将学校细分成了学院、专业、班级,学生入校后,为了方便管理学生,从而诞生了学号。学号上标明了你所在的学院编号、专业编号。能够通过学号找到某人,不是学号本身的功能,而是学校以学号的模式将学生组织在了一起。
IP地址能够帮助我们找到目标主机,本质上也是一种结果。 不同国家的运营商构建本国的公网与内网,网络构建好了,才诞生了IP,才能通过IP定位主机。
全球IP地址的分配,不是以国家为单位划分的,也不是以国家的人口数量为依据划分的,而是许多因素的综合评估。
各个国家之间的网络如何建立通信?通过海底光缆、卫星 等,建立全球骨干网络。
真实的网络结构非常复杂,既涉及到划分公网IP的组织(ICANN),还要在全球范围内进行区域划分(比如亚太、北美、欧洲等),又要考虑各个国家内部的ISP(互联网服务提供商),整体拓扑非常复杂。我们简化所有过程,简单理解公网即可。
全球国家很多,IP地址共32位比特位。为了便于理解,我们假设 用前8位来表示不同国家(实际分配并非如此简单)。各个国家通过海底光纤或者卫星来实现网络通信。每个国家都有出入口路由器,这些出入口路由器接入到全球骨干网络,每个路由器在公网都有自己的IP地址。
简化的公网模型如下所示:

这些路由器是各个国家内网到公网的出入口路由器,大家都接入全球骨干网络。
这些路由器都会在公网中建立通信,将自己的路由信息广播给公网中的其它路由器,其它路由器接收到信息后,将IP地址记录到自己的路由表条目中。
站在中国的角度,每个省级的出入口路由器都横跨两个网络:
- 连接国际骨干网的是某个公网IP(比如示例中的5.0.0.1)
- 连接国内骨干网的是另一个公网IP(比如示例中的5.6.0.1)
国家内部也需要一个公网的环境。我们国家的省份很多,报文可能需要从一个省份发送到另一个省份。为了区分各个省份,在简化模型中可以用IP地址中的若干比特位来区分(实际上IP地址划分没有这么简单)。
每个省也有自己的出入口路由器。运营商们搭建好国内骨干网络,每个省份的出入口路由器将自己的路由信息广播给国内公网中的其它路由器,各个路由器建立自己的路由表条目,它们知晓全国范围内的IP地址(至少知道路由方向)。
在省级的出入口路由器广播自己的路由信息时,中国的国际出入口路由器也能接收到,因此它的路由表条目既有国外的,也有国内的。
跨国通信的流程
假设俄罗斯某台主机向中国某台主机发送信息,目标IP地址为5.1.0.1(假设5开头代表中国):
- 俄罗斯的主机判断目标IP不在本局域网内,将报文向上交付
- 俄罗斯国内的路由器逐级转发,最终到达俄罗斯的国际出入口路由器
- 俄罗斯的国际出入口路由器在路由表中查询,发现5.0.0.0/8网段指向中国,于是将报文发送到全球骨干网络
- 报文经过骨干网络传输,最终被中国的国际出入口路由器接收
- 中国国际出入口路由器在自己的路由表中查询,确定目标主机在陕西省(假设5.1.x.x分配给陕西)
- 为了区分市,继续用IP地址中的若干比特位做区分。到了市级之后,就不再使用公网IP进行细化定位了,而是使用子网内的私有IP
以上用IP地址前8位区分国家的说法是一个极度简化的理解模型,实际情况要复杂得多。IP地址分配不是按国家固定前缀的,而是通过BGP(边界网关协议)动态路由和CIDR聚合来实现全球路由的。
报文从内网到公网的逐级转发过程
某台主机要向IP地址为6.0.100.200的主机发送信息(假设6.0.0.0/8是某个国家的公网网段):
- 主机:判断目标IP不在本局域网内,将报文发给家用路由器
- 家用路由器 :进行NAT转换,将源IP地址改成家用路由器的WAN口IP(私有或公有,取决于上级网络);查家用路由器的路由表,没有找到6.0.100.200的具体条目,根据缺省路由(默认路由),向上交付给上级路由器(比如市级路由器)
- 市级路由器:同样可能进行NAT(如果是多层NAT环境);查找市级路由器的路由表,仍然没有找到6.0.100.200的具体条目,继续向上交付给省级出入口路由器
- 省级出入口路由器 :查找路由表,如果发现目标IP不属于本省范围,继续向上交付给国家骨干路由器
- 国家骨干路由器(国际出入口路由器):在路由表中查询,最终找到目标IP地址6.0.100.200所属的国家或区域,将报文发往对应的国际出入口路由器
- 目标国家的网络:对方的国际出入口路由器收到报文后,逐级向下转发(省级 → 市级 → 家用路由器 → 目标主机)
互联网公司的内网机房也是如此(多层路由结构)。国际如此,省内如此,市内也是如此。
报文在进行转发的过程中,本质就是淘汰的过程 :每一跳路由器都根据目标IP地址和自己的路由表,排除掉不可能的方向,逐步缩小范围。IP地址大大提高了检索效率:因为通过子网掩码和网络号,可以在路由表中快速匹配、快速淘汰,而不需要遍历全世界所有主机
6. 路由
路由的过程,就是这样一跳一跳(Hop by Hop)"问路"的过程,查表的过程就是路由的过程。
所谓"一跳"就是数据链路层中的一个区间,具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间。
IP数据包的传输过程也和问路一样:
- 当IP数据包到达路由器时,路由器会先查看目的IP
- 路由器根据路由表决定这个数据包是能直接发送给目标主机,还是需要发送给下一个路由器
- 依次反复,一直到这达目标IP地址
如果目的IP命中了路由表中的某个条目(非default),就直接按照该条目转发即可。
路由表中的最后一行(通常是default行),主要由下一跳地址 和发送接口 两部分组成。当目的地址与路由表中其它行都不匹配时,就按**缺省路由(默认路由)**条目规定的接口发送到下一跳地址。
那么如何判定当前这个数据包该发送到哪里呢?这个就依靠每个节点内部维护的一个路由表。
路由表可以使⽤ route 命令查看

- Destination:目标网络地址
- Gateway:下一跳地址(0.0.0.0 表示不需要经过中间路由器,直连即可)
- Genmask:子网掩码,用于匹配目标IP是否属于这个网络
- Flags:路由标志(U表示启用,G表示使用网关,H表示目标是主机)
- Iface:从哪个网络接口发送出去
- default(0.0.0.0/0)那条就是缺省路由,匹配所有没有明确条目的目的IP
- Genmask(子网掩码)就是配置在路由器中的,子网划分正是通过路由器配置子网掩码来实现的
- Gateway 列如果是 0.0.0.0,说明目的网络与当前路由器直连,不需要经过下一跳路由器
每一跳路由器的工作就是:
- 取出数据包中的目标IP地址
- 将目标IP与路由表中的每条条目(按子网掩码长度从长到短)进行匹配
- 找到最长匹配的条目
- 按照该条目指定的下一跳地址 和接口将数据包转发出去
- 如果没有匹配到任何条目,则使用缺省路由(如果有配置)
这个过程逐跳重复,直到数据包到达目标主机所在的子网,最后一跳路由器将数据包直接交付给目标主机(此时Gateway为0.0.0.0,表示直连)。
这就是"问路"的本质 :每个路由器只知道"下一步该给谁",不需要知道全路径。