一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
前言
在上一篇文章中,我们从 IP 模块的视角来了解了网络包发送的整体流程,本篇文章我们学习的是 IP 头部时如何生成的。
IP 头部格式
IP 模块接受 TCP 模块的委托负责包的收发工作,它会生成 IP 头部并附加在 TCP 头部前面。
首先我们先来了解一下 IP 的头部格式,IP 头部包含的内容如下图所示,其中最重要的内容就是 IP 地址,它表示这个包应该发送哪里去。这个地址是由 TCP 模块告知的,而 TCP 又是在执行连接操作时从应用程序那里获得这个地址的,因此这个地址的最初来源就是应用程序。IP 不会自行判断包的目的地,而是将包发往应用程序指定的接收方,即便应用程序指定了错误的 IP 地址,IP 模块也只能照做。当然,这样做可能会出错,但这个责任应该由应用程序来承担。
字段名称 | 长度(比特) | 含义 |
---|---|---|
版本号 | 4 | IP 协议版本号,目前使用的是版本 4 |
头部长度(IHL) | 4 | IP 头部的长度。可选字段可导致头部长度变化,因此这里需要执行头部的长度 |
服务类型(Tos) | 8 | 表示包传输优先级。最初的协议规格里对这个参数的规定很模糊,最近 DiffServ 规格重新定义了这个字段的用法 |
总长度 | 16 | 表示 IP 消息的总长度 |
ID 号 | 16 | 用于识别包的编号,一般为包的序列号。如果一个包被 IP 分片,则所有分片都拥有想用的 ID |
标志(Flag) | 3 | 该字段有 3 个比特,其中 2 个比特有效,分别代表是否允许分片,以及当前包是否为分片包 |
分片偏移量 | 13 | 表示当前包的内容为整个 IP 消息的第几个字节开始的内容 |
生存时间(TTL) | 8 | 表示包的生存时间,这是为了避免网络出现回环时一个包永远在网络中大专。每经过一个路由器,这个值就会减 1,减到 0 时这个包就会被丢弃 |
协议号 | 8 | 协议号表示协议的类型(以下皆为 16 进制)TCP:06;UDP:11;ICMP:01 |
头部校验和 | 16 | 用于检查错误,现在已不使用 |
发送方 IP 地址 | 32 | 网络包发送方的 IP 地址 |
接收方 IP 地址 | 32 | 网络包接收方的 IP 地址 |
可选字段 | 可变长度 | 除了上面的头部字段之外,还可以添加可选字段用于记录其他控制信息 |
发送方 IP 地址
IP 头部中还需要填些发送方的 IP 地址,大家可能认为是发送方计算机的 IP 地址,实际上“计算机的 IP 地址”这种说法并不准确。一般的客户端计算机上只有一块网卡,因此也就只有一个 IP 地址,这种情况下我们可以认为这个 IP 地址就是计算机的 IP 地址,但如果计算机上游多个网卡,情况就没有那么简单了。
IP 地址实际上并不是分配给计算机的,而是分配给网卡的,因此当计算机存在多块网卡时,每一块网卡都会有自己的 IP 地址。
很多服务器上都会安装多块网卡,这时一台计算机就有多个 IP 地址,在填写发送方 IP 地址时就需要判断到底应该填写哪个地址。这个判断相当于在多块网卡中判断应该使用那一块网卡来发送这个包,也就相当于判断应该把包发往哪个路由器,因此只要确定了目标路由器,也就确定了应该使用哪块网卡,也就确定了发送方的 IP 地址。
IP 头部的“接收方 IP 地址”填写通信对象的 IP 地址。
发送方 IP 地址需要判断发送所使用的网卡,并填写该网卡的 IP 地址。
那么,我们应该如何判断应该把包交给哪块网卡呢?其实是和路由器使用 IP 表判断下一个路由器位置的操作是一样的。因为协议栈的 IP 模块与路由器中负责包收发的部分都是根据 IP 协议规则来进行收发操作的,所以它们也都用相同的方法来判断把包发送给谁。
路由表
Linux 系统可以通过 route print
命令来显示路由表,Mac 系统可以通过 netstat -nr
命令来查看。
➜ ~ netstat -nr
Routing tables
Internet:
Destination Gateway Flags Netif Expire
0/1 utun2 USc utun2
default 192.168.0.1 UGSc en0
default link#20 UCSI utun2
1.180.235.194 link#20 UHWIi utun2
1.193.218.76 link#20 UHW3I utun2 82
8.8.4.4 link#20 UHWIi utun2
8.8.8.8 link#20 UHW3I utun2 188
8.133.123.139 link#20 UHWIi utun2
10.5.112.222 10.5.112.222 UH utun2
10.8.7.220 link#20 UHWIi utun2
10.8.7.224 link#20 UHWIi utun2
10.8.8.18 utun2 UHS utun2
10.8.8.18/32 utun2 USc utun2
10.227.76.230 192.168.0.1 UGHS en0
17.57.145.132 link#20 UHWIi utun2
23.200.24.64 link#20 UHW3I utun2 117
23.200.24.88 link#20 UHW3I utun2 101
192.168.0.1 d0:76:e7:67:2d:ba UHLWIir en0 1198
192.168.0.104/32 link#9 UCS en0 !
192.168.0.106 e8:9f:6d:a9:14:1c UHLWI en0 1097
224.0.0/4 link#9 UmCS en0 !
224.0.0/4 link#20 UmCSI utun2
224.0.0.251 1:0:5e:0:0:fb UHmLWI en0
239.255.255.250 1:0:5e:7f:ff:fa UHmLWI en0
239.255.255.250 link#20 UHmW3I utun2 209
255.255.255.255/32 link#9 UCS en0 !
255.255.255.255/32 link#20 UCSI utun2
Internet6:
Destination Gateway Flags Netif Expire
default fe80::%utun0 UGcI utun0
default fe80::%utun1 UGcI utun1
通过 netstat -nr
命令我们可以看到路由表,有 IPV4 路由表和 IPV6 路由表。这里我们主要关注 IPV4 路由表,我们先来看看每个字段的含义。
Network Destination
:表示网络包的最终目的地;Netmask
:目标地址掩码;Gateway
:转发路由器的 IP 地址。如果本列与右边的 Interface 列内容想用,则表示不通过路由器转发,可直接向目标 IP 地址发送包;Interface
:发送包的网络接口。当匹配到本条路由时,就会使用这一列中的 IP 地址对应的网络接口向左侧王冠中的路由器发送包;Metric
:通过这条路由传送包的成本,这个数越小说明距离越近;
接着我们来看下如何选择网卡。
首先,我们对套接字中记录的目的地 IP 地址与路由表左侧的 Network Destination
栏进行比较,找到对应的一行。例如,TCP 模块告知的目标 IP 地址为 192.168.0.21
,那么就对应上面路由表中的 192.168.0.*
的那列,然后将包发送给对应的路由器。
default 192.168.0.1 UGSc en0
这列表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。
这样一来,我们就可以判断出应该使用哪块网卡来发送包了,然后就可以在 IP 头部的发送方 IP 地址中填上这块网卡对应的 IP 地址。
接下来还需要填写协议号,它表示包的内容是来自哪个模块的。例如,如果是 TCP 模块委托的内容,则设置为 06
(十六进制),如果是 UDP 模块委托的内容,则设置为 17
(十六进制),这些值都是按照规则来设置的。在现在我们使用的浏览器中,HTTP 请求消息都是通过 TCP 来传输的,因此这里就会填写表示 TCP 的 06
(十六进制)。
对于 IP 头部的其他字段也需要填入相应的值,但是对大局没有什么影响,这里我们就先不学习了。
总结
IP 地址实际上并不是分配给计算机的,而是分配给网卡的,因此当计算机存在多块网卡时,每一块网卡都会有自己的 IP 地址。
IP 头部的“接收方 IP 地址”填写通信对象的 IP 地址。
发送方 IP 地址需要判断发送所使用的网卡,并填写该网卡的 IP 地址。
参考文档
- 《网络是怎样连接的》—— 户根勤
往期文章
- 网络是怎样连接的(一)—— 浏览器访问 Web 服务器过程概览
- 网络是怎样连接的(二)—— 浏览器生成 HTTP 消息
- 网络是怎样连接的(三)—— 通过 DNS 服务器查询 IP 地址
- 网络是怎样连接的(四)—— DNS 服务器工作介绍
- 网络是怎样连接的(五)—— 委托操作系统进行收发消息过程概览
- 网络是怎样连接的(六)—— 协议栈内部探索步骤
- 网络是怎样连接的(七)—— 协议栈的内部结构
- 网络是怎样连接的(八)—— 探索套接字
- 网络是怎样连接的(九)—— 连接连的到底是啥
- 网络是怎样连接的(十)—— 连接操作的实际过程
- 网络是怎样连接的(十一)—— 协议栈发送数据特性
- 网络是怎样连接的(十二)—— 数据收发操作中重要标志位 ACK
- 网络是怎样连接的(十三)—— 从服务器断开并删除套接字
- 网络是怎样连接的(十四)—— 网络包传输概览(IP 模块视角)
- 网络是怎样连接的(十五)—— 网络包传输概览(IP 模块视角)