《TCP/IP协议卷1》第3章 IP协议
3.1 引言
IP是TCP/IP协议族核心协议,TCP、UDP、ICMP及IGMP数据都以IP数据报格式传输。IP提供不可靠、无连接的数据报传送服务。不可靠指不能保证数据报成功到达目的地,出错时丢弃数据报并发送ICMP消息给信源端,可靠性由上层协议(如TCP )保障;无连接指不维护后续数据报状态信息,数据报处理相互独立,可无序接收。
3.2 IP首部
- 基本格式与传输顺序:IP数据报普通首部长20字节,除非含选项字段。4字节32bit值按big endian(大端)顺序传输,即网络字节序,非此格式机器传输前需转换。目前协议版本号是4 ,即IPv4 。首部长度字段占32bit中4比特,因以4字节为单位,普通IP数据报(无选项)此字段值为5 。
- 服务类型(TOS)字段:含3bit优先权子字段(现被忽略 )和4bit TOS子字段,分别代表最小时延、最大吞吐量、最高可靠性和最小费用,4bit中只能置1bit ,全为0表示一般服务。多数TCP/IP实现曾不支持TOS特性,新系统及路由协议(如OSPF、IS - IS )可据此进行路由决策 。不同应用对TOS设置不同,如Telnet/Rlogin要求最小时延,FTP要求最大吞吐量等 。
- 总长度字段:表示整个IP数据报长度(字节为单位 ),可确定数据内容起始位置和长度,16比特,数据报最长可达65535字节。链路层常对过长数据报分片,多数主机要求不接收超576字节数据报,不过很多实现允许超8192字节的IP数据报。
- 标识字段:唯一标识主机发送的每份数据报,通常每发送一份报文值加1 ,RFC 791认为应由发送数据报的上层选择 。
- TTL(生存时间)字段:设置数据报可经过的最多路由器数,初始值由源主机设(常为32或64 ),每经一个路由器值减1 ,值为0时数据报被丢弃并发送ICMP报文通知源主机 。
- 协议字段:用于识别哪个协议向IP传送数据 。
- 首部检验和字段:根据IP首部计算检验和码,不对首部后数据计算。发送方对首部每个16bit进行二进制反码求和存于此字段,接收方同样计算,若首部无差错结果应为全1 ,否则丢弃数据报,ICMP、IGMP、UDP和TCP首部也有类似检验和码 。
- IP地址字段:每份IP数据报包含源IP地址和目的IP地址,均为32bit值 。
- 选项字段:可变长可选信息,包括安全和处理限制、记录路径、时间戳、宽松的源站选路、严格的源站选路等,很少使用,非所有主机和路由器都支持。选项字段以32bit为界限,必要时插入值为0的填充字节保证首部始终是32bit整数倍 。
3.3 IP路由选择
- 基本概念:对于主机,若目的主机与源主机直接相连(如点对点链路 )或在共享网络(以太网、令牌环网 )上,IP数据报直接发送到目的主机;否则发往默认路由器,由其转发。多数主机是简单机制。如今多数多用户系统(如Unix系统 )可配置成路由器或主机,路由器转发数据报,主机默认不转发(特殊设置除外 )。
- IP层工作机制:IP层可接收本地生成(来自TCP、UDP、ICMP、IGMP )或待转发(从网络接口接收 )的数据报并发送。IP层内存有路由表,收到数据报时进行搜索。先检查目的IP地址是否为本机地址或IP广播地址,若是则交给IP协议模块处理;若不是,若IP层设为路由器功能则转发,否则丢弃。
- 路由表信息及路由选择步骤:
-
- 路由表信息:路由表每项包含目的IP地址(可以是主机地址或网络地址,由标志字段指定 )、下一站路由器IP地址(指直接相连网络上的路由器,用于转发数据报 )、标志(指示下一站路由器是真正下一站还是直接相连接口 )、为数据报指定的网络接口 。
- 路由选择步骤:
-
-
- 搜索路由表,寻找与目的IP地址完全匹配的表目(网络号和主机号都匹配 ),找到则按表目指定发送报文(取决于标志字段 )。
- 搜索路由表,寻找与目的网络号匹配的表目,找到则按其指定发送报文(取决于标志字段 )。此过程需考虑子网掩码。
- 搜索路由表,寻找标为“默认(default)”的表目,找到则按其指定发送报文。若上述步骤都不成功,数据报无法传送,若来自本机则生成“主机不可达”或“网络不可达”错误报文返回。
-
- IP路由选择机制特点:IP路由选择仅为数据报传输提供下一站路由器IP地址,假定下一站路由器更接近目的且与主机直接相连。它是一个强大机制,为每个主机指定一个路由器,极大缩小路由表规模,且每个主机不必了解完整路径,Internet上路由器数量远小于100万个。
3.4 子网寻址
- 子网编址原因与概念:如今主机都需支持子网编址(RFC 950 )。传统IP地址由网络号和主机号组成,而子网编址是将主机号进一步分成子网号和主机号。这是因为A类和B类地址为主机分配空间过多(A类可容纳 个主机,B类可容纳 个主机 ),实际网络中无需这么多主机,且全0或全1的主机号无效,所以要减去2 。在Internet获得某类IP网络号后,系统管理员决定是否建立子网及分配给子网号和主机号的比特数 。
- 子网划分示例:以B类网络地址140.252为例,剩余16bit中,可将8bit用于子网号,8bit用于主机号,这样就有254个子网,每个子网有254台主机 。许多管理员常将B类地址留给主机的16bit中前8bit作为子网地址,后8bit作为主机号,便于用点分十进制表示法确定子网号,但不强制A类或B类地址子网划分以字节为界限。子网在C类地址也可使用,只是可用比特数较少,A类地址子网例子少见,因其本身数量少且多是进行子网划分 。
- 子网对外部和内部路由器的影响:
-
- 对外部路由器:子网对外部路由器隐藏内部网络组织细节。如网络中所有IP地址有B类网络号140.252 ,含超30个子网、超400台主机,由一台路由器提供Internet接入。外部路由器只需知道通往140.252.104.1的路径就能到达该网络,将B类地址划分子网可缩小Internet路由表规模,若用30个C类地址则需30个路由表目 。
- 对内部路由器:子网对内部路由器不透明。如来自Internet的数据报到达gateway,gateway需知道目的地址在子网57 ,然后转发到kpn0 ,kpn0再转发到R55 ,R55转发到R57 。
3.8 ifconfig命令
ifconfig命令用于在引导时配置主机网络接口,因拨号接口(如SLIP链路 )会频繁接通和挂断,每次都需运行该命令,具体运行方式取决于所使用的SLIP软件。通过展示作者子网接口的相关参数示例,解释了不同网络接口(以太网接口、环回接口、SLIP接口等 )在该命令下显示的标志(如广播、点到点连接、可压缩SLIP等 )、IP地址、子网掩码等信息,以及不同系统(SunOS、4.4BSD )使用该命令时的差异 。
3.9 netstat命令
netstat命令可提供系统上的接口信息,使用 -i参数打印接口信息, -n参数打印IP地址而非主机名。通过示例展示了接口的MTU、网络地址、输入分组数、输入错误、输出分组数、输出错误、冲突及当前输出队列长度等信息。第9章将用其检查路由表,第13章用于分析改进版广播活动的广播组 。
3.10 IP的未来
IP存在三个方面问题:过半B类地址已被分配,预计1995年耗尽;32bit的IP地址从长期看难以满足Internet增长需求;当前路由结构无层次,随网络数目增长,路由表规模不断增大 。无类别域间路由选择(CIDR)对当前IPv4进行扩充以解决第三个问题,第10.8节将详细介绍 。
关于新版IP(下一代IP,常称IPng )主要有四个方面建议:
- SIP(简单Internet协议):对当前IP最小幅度修改,采用64位地址和不同首部格式,首部前4比特仍含协议版本号(非4 )。
- PIP:采用更大、可变长度且有层次结构的地址,首部格式也不同。
- TUBA:基于OSI的CLNP(无连接网络协议 ),提供更大地址空间,已有相关文档,许多路由器支持CLNP,但主机支持较少。
- TP/IX:虽SIP采用64bit地址,但它改变了TCP和UDP格式(端口号、序列号、确认号、TCP窗口等 ),且前三个建议基本采用相同版本的TCP和UDP作为传输层协议 。由于四个建议只能选其一作为IPv4的替换者,且CIDR虽能解决短期问题,但IPv4后继者的确定仍需时间讨论 。
🌍 思考:ip 数据报最大长度为 65535。这个长度和 MTU 不是冲突了吗?还有 IP 数据报首部的片偏移是超过 65535 字节才分片吗?
一、IP 数据报最大长度为什么是 65535 字节?
在 IPv4 协议中,IP 数据报的总长度字段(Total Length)是一个 16 位字段,因此它的取值范围是:
0 到 2^16 - 1 = 65535 字节
也就是说,IP 数据报的最大理论长度是 65535 字节(包括首部和数据部分)。
但这只是一个协议层面的上限,并不代表在实际网络中可以发送这么大的数据包。
二、那这个长度与 MTU 是否冲突?
不冲突,因为这是两个不同层级的概念:
概念 | 含义 | 举例 |
IP 数据报最大长度 | 是 IP 层允许的数据报最大尺寸(逻辑上限) | 最大可达 65535 字节 |
MTU | 是链路层(如以太网)对帧所能承载的数据量限制(物理/网络设备限制) | 一般为 1500 字节 |
✅ 实际传输时的处理方式:
当一个 IP 数据报的大小超过了路径上某个链路的 MTU,就会触发**分片(Fragmentation)**机制,把一个大的 IP 数据报分成多个较小的数据报进行传输。
例如:
- 假设你构造了一个 5000 字节的 IP 数据报;
- 路径上的 MTU 是 1500 字节;
- 那么该数据报会被分片成多个小数据报,每个不超过 1500 字节。
三、片偏移(Fragment Offset)和分片机制详解
IP 首部中的几个关键字段用于控制分片:
- DF(Don’t Fragment)标志位:若为 1,则禁止分片;
- MF(More Fragments)标志位:表示是否还有更多分片;
- Fragment Offset(片偏移):指示当前分片在原始数据报中的位置,单位是 8 字节块(不是字节)。
片偏移的作用:
- 片偏移字段是 13 位,所以最大值为:
2^13 - 1 = 8191
- 因为它是以 8 字节为单位,所以最大偏移量为:
8191 × 8 = 65528 字节
这说明,一个 IP 数据报最多只能支持到 65528 字节的偏移,即最大数据报长度不能超过:
65528 + 8 = 65536 字节
但受限于 Total Length 字段(16 位),最大只能是 65535 字节。
“IP 数据报首部的片偏移是超过 65535 字节才分片吗?”
✅ 正确理解应该是:
- 分片是在 IP 数据报长度超过路径 MTU时发生的;
- 片偏移只是用来标识各个分片在原始数据报中的位置;
- 片偏移的最大值是 65528 字节(基于 8 字节单位);
- 所以整个数据报的最大长度不能超过 65535 字节,否则无法用片偏移完整描述。
🌍 思考:如何查看 linux 系统的最大的 ip 层数据包是多少?这个数据对网络的性能影响大吗?
使用 ifconfig 命令
ubuntu@VM-0-9-ubuntu:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.206.0.9 netmask 255.255.240.0 broadcast 10.206.15.255inet6 fe80::5054:ff:fe66:7b80 prefixlen 64 scopeid 0x20<link>ether 52:54:00:66:7b:80 txqueuelen 1000 (Ethernet)RX packets 1771 bytes 366971 (366.9 KB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 1358 bytes 2515241 (2.5 MB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen 1000 (Local Loopback)RX packets 603 bytes 2036004 (2.0 MB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 603 bytes 2036004 (2.0 MB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
mtu 为 1500 字节。
MTU 对网络性能的影响
MTU 的大小确实对网络性能有影响:
- 较大的 MTU:对于大型数据传输来说效率更高,因为每个包携带的数据更多,减少了包头开销,并且减少了发送同样数量数据所需的总包数。然而,过大的 MTU 可能会导致延迟增加,特别是在网络条件不稳定或存在较高错误率的情况下。
- 较小的 MTU:虽然降低了单个数据包丢失时的影响,并且在网络状况不佳时有助于减少重传的数据量,但它会增加总的包头开销,导致额外的处理负荷并可能降低吞吐量。
因此,选择合适的 MTU 值对于优化网络性能至关重要。理想情况下,MTU 应根据具体的网络环境进行调整。例如,在以太网环境中,默认的 MTU 值通常是 1500 字节。
🌍 习题:环回地址必须是127.0.0 .1吗 ?
环回地址并不必须是 127.0.0.1,但它确实是使用最广泛的一种形式。在IPv4中,整个 127.0.0.0/8 地址块(即从 127.0.0.0 到 127.255.255.255 的范围)都被预留用于环回(loopback)目的。
然而,在实际应用中,127.0.0.1 是最常见的选择,它通常被称为“localhost”,用于指向本地计算机。这样做主要是出于方便和标准化考虑,以便所有系统都遵循同一约定,从而简化网络配置和应用程序开发。
简而言之,虽然理论上你可以使用 127.0.0.0/8 范围内的任何地址作为环回地址,但为了保持一致性和避免混淆,推荐并最常用的是 127.0.0.1。此外,许多软件和服务默认配置为使用 127.0.0.1 进行本地通信。因此,除非有特定需求,否则最好坚持使用 127.0.0.1 作为环回地址。
🌍 思考:环回地址有什么用?环回地址数据会经过 TCP/ip 协议栈吗?会经过网卡吗?
本地网络服务测试:开发人员可以使用环回地址来测试服务器端软件或服务是否正常工作,例如Web服务器、数据库服务器等。通过访问 http://localhost
或 http://127.0.0.1
,可以在不连接外部网络的情况下验证服务的功能。
环回地址的数据确实会经过TCP/IP协议栈,但不会通过物理网卡进行传输。
经过TCP/IP协议栈
当您发送数据到环回地址(如 127.0.0.1
在IPv4中或 ::1
在IPv6中),这些数据包会像其他任何网络通信一样被送入TCP/IP协议栈处理。这意味着它们将经历与常规网络流量相似的处理过程,包括但不限于:
- IP层处理:包括确定目标地址、查找路由等。
- 传输层处理:如果是基于TCP或UDP的数据,还会涉及到端口的选择和管理。
然而,由于这是环回接口上的通信,操作系统知道这些数据包不需要离开本机,因此它优化了这个过程以避免不必要的操作。
不经过物理网卡
尽管环回数据包会进入并由TCP/IP协议栈处理,但是这些数据包不会被发送到物理网络适配器(即网卡)。相反,它们在内部被直接传递给协议栈的接收端,仿佛是从网络接收到的一样。这种机制允许操作系统高效地处理本地回路通信,同时避免了物理网络传输带来的延迟和其他开销。