一. 网络层
1. 理解传输层和网络层

当我们让两台主机进行通信时,并非直接由发送端的传输层到接收端的传输层,而是需要通过网络协议栈的封装以及多个路由的转发。本文将深入探讨这一过程。
2. IP协议的核心作用与构成
IP协议的主要功能是将数据包从A主机跨网络传输至B主机。然而,具备这种能力是否意味着能够确保数据包的成功传输呢?实际上并非如此,尽管大部分情况下可以实现。这是因为网络中可能存在拥堵,或者网络设备可能出现故障等,导致无法百分之百地保证数据包的传输。在网络层中,实际传输的是IP报文。
IP协议解决的是数据包的传输能力问题,而TCP协议则解决了策略问题,例如如何处理丢包、超时及异常情况。因此,TCP/IP协议的核心功能在于确保数据能够从A主机可靠地跨网络传输至B主机,这是网络的核心问题和功能所在。
为了实现数据包的传输,需要标识通信双方主机的唯一性,因此每台主机都需要设定一个IP地址(公网IP)。IP协议解决的是主机到主机的问题,而TCP协议则解决了进程到进程的问题,因为它涉及到端口号。
可以用一个简单的例子来解释数据包的传输过程:就像去故宫游玩前需要先到达北京一样,数据在网络中的传输也需要先将数据包送达目标主机所在的局域网。
IP地址由目标网络号和目标主机号组成。对路由的理解在于,数据包在网络上传输的本质是从一个子网到另一个子网,而每个子网同样需要唯一的标识。因此,IP地址中必须包含目标网络的信息。
提示:传统的路由器工作在网络层,而现代的路由器已经发展成为小型计算机,可以在应用层工作。
3. IP协议报头解析
1. 协议本质上是一种结构体,在内核中表现为iphdr。

在内核中的IP协议表示为:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};
2. 报头的标准长度为20字节,首部长度的单位也是4字节,因此四位首部的值应为0101(20/4=5)。
无论是哪种协议,都需要解决以下两个基本问题:
- IP报文解包问题:报头固定长度为20字节,先读取前20字节以获取四位首部长度,然后用16位总长度减去报头长度,即得数据部分的长度。
- IP分用问题:八位协议字段指示有效载荷是UDP还是TCP,从而实现准确的向上层交付。
3. 八位服务类型包括:3位优先级字段(已废弃),4位TOS字段,和1位保留字段(必须为0)。4位TOS字段分别表示最小延迟、最大吞吐量、最高可靠性和最低成本。这四个特性相互冲突,只能选择其中一个。对于像SSH/Telnet这样的应用程序,最小延迟较为重要;而对于FTP这样的程序,最大吞吐量更为关键。
4. 八位生存时间(TTL):随着全球网络拓扑结构的日益复杂,报文需要通过路由算法转发。如果出现错误,可能会导致报文在局域网中循环转发。TTL实际上是一个计数器,用于记录报文的存活时间,当达到一定时间后,若报文无法正常转发,则采取相应措施。
5. 16位首部检验和:虽然IP协议不主要负责可靠性传输,但仍需确保报文本身的正确传输。
6. 源IP和目的IP:用于标识报文的来源和目的地。
4. 子网划分
1. 网络是经过多年发展和规划的结果,这意味着网络的设计是有目的性的。要理解报文如何路由,就需要了解网络是如何被设计的。
为什么需要进行子网划分?可以通过一个例子来说明:假设在一个学校中有多个学院,每个学院有自己的编号,学生的学号由学院编号+班级+班级排名组成。

假设张三捡到了一个钱包,只能看到学号。作为普通学生,张三不知道06开头的学院是哪个,更不知道这个学号对应的具体学生。因此,他留下了自己学号和电话号码,将信息传递给本院学生会主席,并在院群中发布相关消息。
这里的学院编号相当于子网,每个学生则相当于源主机和目标主机,而每个院的主席相当于连接学院的路由器。一个学生编号01123 = 01计算机学院 + 123学生号。在其他学院中也可能有123的学生号,但学院编号加上学号一定是唯一的。
网络的组织方式类似于学校的这种结构,是在我们入学前就已经设计好的。设计者通常是运营商。子网划分的过程类似于给每个学院分配编号。
为什么需要进行子网划分?路由报文的本质是查找主机的问题,而查找的本质是排除问题(确定哪些是目标,哪些不是)。报文在传输过程中只关注网络号,一旦确定了网络号,就可以迅速排除其他子网,大幅提高查找效率。

路由器至少配备两个网卡,可以配置IP地址。计算机中的IP地址来自何处?未联网的计算机没有IP地址,通常是由家庭路由器通过DHCP协议分配的(内部网络)。
有一种技术称为DHCP,可以自动为内部网络中新添加的主机节点分配IP地址,避免了手动管理IP地址的麻烦。一般的路由器都具有DHCP功能,因此路由器也可以被视为一个DHCP服务器。
2. 在过去,存在一种网络划分方法:分类划分法。

根据IP地址的分类标准,可以将其分为以下几类:
- A类:从0.0.0.0至127.255.255.255
- B类:从128.0.0.0至191.255.255.255
- C类:从192.0.0.0至223.255.255.255
- D类:从224.0.0.0至239.255.255.255
- E类:从240.0.0.0至247.255.255.255
子网划分涉及将32位的二进制数字分割,以确定网络标识部分的长度。
资源的概念基于其有用性和稀缺性。上述IP地址分配方法导致了资源的快速耗尽,尤其是各国的网络供应商为了建立国家子网而争夺这些资源。
随着互联网的快速发展,原有的地址分配方案暴露出诸多局限。许多组织倾向于申请B类网络地址,导致这类地址迅速耗尽,而A类地址则因分配过多而造成浪费。
例如,一个B类地址理论上可以容纳超过65,000台主机,而A类地址的容量更大。然而,在实际网络建设中,很少会有如此大规模的网络需求,导致大量IP地址未被充分利用。
为应对这一挑战,引入了CIDR(无类别域间路由)和子网掩码的新机制。
CIDR(无类别域间路由)
CIDR通过将IP地址与子网掩码进行按位与运算,来确定网络号。

子网掩码由一系列连续的1后跟0组成,1的数量决定了网络号的长度。子网掩码帮助定义了网络中可能的最大主机数量。尽管分类和子网掩码是在不同发展阶段产生的,但它们之间没有冲突。
特殊IP地址说明
- 当主机部分全部为0时,表示网络号,用于标识特定的局域网。
- 当主机部分全部为1时,表示广播地址,用于向同一链路上的所有主机发送数据包。
- 127.* 的IP地址用于本机环回测试,最常用的是127.0.0.1。
IP地址的数量限制
IPv4地址是一个32位的正整数,总共提供大约43亿个地址。然而,实际可用的IP地址少于这个数字,因为某些地址被预留用于特殊用途。此外,每个网络接口卡都需要配置一个或多个IP地址,而不是按主机数量配置。
CIDR在一定程度上缓解了IP地址短缺的问题,提高了利用率并减少了浪费,但并未从根本上解决地址资源的绝对上限问题。为了解决这一问题,提出了三种方法:
- 动态分配IP地址:仅向接入网络的设备分配IP地址,同一MAC地址的设备每次连接互联网时可能获得不同的IP地址。
- NAT技术:将在后续章节详细介绍。
- IPv6:IPv6并非IPv4的简单升级,而是完全独立的协议,使用128位地址空间,但目前尚未广泛普及。
运营商与内外网
网络通常被划分为公网和内网,后者也称为子网或局域网,两者呈一对多的关系。专用于内网的IP地址包括:
- 10.*:前8位作为网络号,共包含16,777,216个地址。
- 172.16.* 至 172.31.*:前12位作为网络号,共包含1,048,576个地址。
- 192.168.*:前16位作为网络号,共包含65,536个地址。
在网络通信中,私有IP地址不允许直接出现在公共网络上。
普通用户直接接触到的网络通常是内网(子网或局域网)。运营商负责为子网内的所有主机分配IP地址,近年来,随着国家政策的支持和技术的发展,上网费用逐渐降低,促进了网络的普及。
当用户联系运营商安装网络时,技术人员会安装必要的设备并连接网线,这些设备连接的是运营商的网络。路由器分为企业级和家用两种,家庭使用的路由器是运营商构建的子网中的一个节点。
子网内的主机可以直接相互通信。家用路由器同样可以构建自己的子网,拥有独立的子网IP,其中的设备都在同一子网内,并能够直接通信。运营商的路由器则有一个公网IP,可以接入广域网,因此被称为公网出入口路由器。

内网IP地址不出现于公网的原因在于,全网中可能存在大量相同内网IP的主机,导致数据包无法正确返回。通过子网掩码,可以判断目标主机是否位于发送方的同一子网。当数据包从内网传输到公网时,家用路由器会用其WAN口的公网IP地址替换原始的源IP地址,确保数据包能够正确到达目的地。

实际上,每当数据通过一个内部网络路由器时,都会执行类似的操作。这里先不深入讨论,这是关于NAT(网络地址转换)的部分。
当我们未按时支付账单时,网络服务会停止,这是因为设置网络时已将个人电话号码和相关信息配置到了路由器中。一旦出现欠费情况,自然就无法继续使用网络了,运营商通过这种方式控制是否将数据包转发至互联网。
此外,我们的安全技术能够检测并阻止含有敏感信息的数据包,防止其被转发到公共网络。
以上提到的是子网和较大的子网概念,那么什么是公网?如何理解子网的划分呢?公网IP由各国的网络服务提供商申请,他们不仅构建内部网络,还要建立覆盖本国的公共网络环境(例如高通、诺基亚、中国联通等)。一个地区的网络规模,很大程度上取决于其拥有的公网IP数量。虽然公网IP的分配并不是简单地按国家进行,而是根据地区网民的数量来决定,但为了简化理解,我们可以假设公网IP是以国家为基础进行分配的。

上图展示了一种网络划分方法,其中前八位表示每个国家的网络编号(假设中国的编号以5开头)。对于中国而言:
0000 0101 0000 0000 0000 0000 0000 0000/8
网络号 主机号
中国:5.0.0.0/8
由于中国包含多个省份,因此需要进一步细分子网,所有省间的路由器共同构成了国内的公共网络。例如,接下来的八位用于子网划分:
0000 0101 0000 0001 0000 0000 0000 0000/16
山西:5.1.0.0/16
按照这种方式,每个城市也会被分配相应的子网。然而,这种方法会导致IP地址迅速耗尽,尤其是考虑到存在许多人口众多的大城市。此时,私有IP地址的重要性就显现出来:同一子网内的IP地址不能重复,但在不同的子网中可以重复使用,这包括一些专门为内部网络设计的特殊IP地址。
每个路由器都是连接两个或多个网络的设备,因此至少需要配置两个IP地址:一个用于外部接口(WAN口IP),另一个用于内部网络(子网IP)。
公网路由器和私网路由器采用不同的路由算法。在同一个公共网络中的主机可以直接相互通信,无需额外配置。从底层来看,网络是由一个个子网汇聚而成的拓扑结构。国际路由器则在国际主干网上广播各自国家的配置信息,以便实现跨网络的数据包交换。
路由是指在网络结构中寻找到达目的地的路径。家庭路由器的默认IP配置通常指向下一跳的地址。路由过程实际上是“一跳一跳”(Hop by Hop)的“寻路”过程。
所谓的“一跳”指的是数据链路层中的一个区间,具体来说,在以太网中是从源MAC地址到目的MAC地址之间的一个帧传输区间。

查询路由表的结果通常有以下几种情况:
- 知道下一跳的去向
- 未找到匹配项,使用默认路由
- 找到通往目标网络的出口,然后将数据转发到内部网络
我们可以通过执行route命令来查看当前云服务器的路由表:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default _gateway 0.0.0.0 UG 100 0 0 eth0
10.0.12.0 0.0.0.0 255.255.252.0 U 100 0 0 eth0
_gateway 0.0.0.0 255.255.255.255 UH 100 0 0 eth0
183.60.82.98 _gateway 255.255.255.255 UGH 100 0 0 eth0
183.60.83.19 _gateway 255.255.255.255 UGH 100 0 0 eth0
需要注意的是,路由表中的Destination表示目标网络地址,Genmask是子网掩码,Gateway是下一跳地址,Iface是发送接口。Flags中的U标志表示该条目有效,G标志表示下一跳地址是某个路由器的地址,没有G标志的条目表示目标网络地址与本机接口直接相连,不需要通过路由器转发。
一个简单的例子:

二. IP报文的分片与重组
数据链路层从上层接收的完整报文,其大小不能超过MTU(最大传输单元)——通常为1500字节。为什么有这样的限制?如果在网络层,一个报文的大小超过了这个值,会怎样处理?在这种情况下,报文将在网络层被分割成多个较小的部分。当这些部分到达接收端时,会再次被重组。重组过程也在网络层完成,传输层传递给网络层的是这些片段。任何一部分的丢失,都会导致整个报文的丢失。如果上层协议是TCP,将会触发重传机制。因此,在网络通信中,过多的分片会增加数据包丢失的风险。
然而,分片与重组并不是常见的做法,而是一种迫不得已的措施。是否进行报文分片,并不由网络层决定。为了尽量避免分片,关键在于传输层的处理方式。传输层传递给网络层的数据报文不应超过1460字节——这个长度即MSS(最大段尺寸),其中包括20字节的标准IP头部和20字节的标准TCP头部。
那么,为什么滑动窗口机制不将数据报打包,而是将其分割成多个部分呢?根本目的是为了减少分片的可能性。

IP报文会被分片,每个分片都有自己的报头。其中包括:
- 16位标识(id): 独特地标识主机发送的报文。如果IP报文在数据链路层被分片,每个分片的这个ID是相同的。
- 3位标志字段: 第一位保留(意味着目前未使用,但未来可能有用)。第二位设置为1表示禁止分片,这种情况下如果报文大小超过MTU,IP模块会丢弃报文。第三位表示“更多分片”,如果是分片的一部分,则设置为1,最后一个分片设置为0,类似于结束标记。
- 13位分片偏移(fragment offset): 表示分片相对于原始IP报文起始位置的偏移量。实际上,它指示了每个分片在重组时相对于原报文的位置。
前部分在原报文中所处的位置,实际偏移的字节数是该值除以8得到的结果。因此,除了最后一个报文外(假设之前的报文长度都是8的整数倍),其他报文的长度也必须是8的整数倍(否则报文将不连续)。
注意:偏移(13位)表示本段数据在其所属的原始数据报数据区中的偏移量(以8字节为单位)。
如何进行分片和组装?
- 首先需要识别特定报文是否被分片:只要分片了,除了最后一个分片外,其他分片的标志位都为1。即使只接收到最后一个标志位为0的分片,其13位片偏移也不为0,这可以帮助我们识别出分片。
- 如果报文已被分片,如何确保接收到同一个报文的所有分片?
- 相同标识的分片需要聚合。未完全接收到的情况可能包括:
- 首片丢失:片偏移为0的分片丢失;
- 末片丢失:没有更多的分片标志位为0的分片;
- 中间片丢失:通过检查起始偏移量加上自身长度是否等于下一个分片的片偏移来判断,然后将所有接收到的分片按片偏移升序排序。
- 相同标识的分片需要聚合。未完全接收到的情况可能包括:
- 组装:作为接收方,当我们确定一个报文已被分片,并且已全部接收,可以直接按照片偏移升序排序来进行组装。


雷达卡


京公网安备 11010802022788号







