一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情。
前言
前面的文章中我们讲述了 IP 模块生成 IP 头部和 MAC 头部。完成了 IP 模块的工作之后,下面就该轮到网卡将网络包发送出去。这部分内容涉及将 IP 包转换成电信号或光信号发送过去,这部分内容我们暂时先不研究,直接探索将服务器的响应包从 IP 传递给 TCP 的过程。
名词解释
ICMP
ICMP(Internet Control Message Protocol)Internet 控制报文协议。它是 TCP/IP 协议簇的一个自协议。用于在 IP 主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本文的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP 使用 IP 的基本支持,就像它是一个更高级别的协议,但是 ICMP 实际上是 IP 的一个组成部分,必须由每个 IP 模块实现。
IP 模块工作步骤
下面我们来看下 IP 模块具体工作步骤。
下面我们假设 Web 服务器返回了一个网络包,那么协议栈会进行哪些处理呢?服务器返回的包的以太类型应该是 0800
,因此网卡驱动程序会将其交给 TCP/IP 协议栈来进行处理。
接下来就轮到 IP 模块先工作了。
第一步是检查 IP 头部,确认格式是否正确。如果格式没有问题,下一步就是查看接收方 IP 地址。如果接收网络包的设备是一台 Windows 客户端计算机,那么服务器返回的包的接收方 IP 地址应该与客户端网卡的地址一直,检查确认之后我们就可以接收这个包了。
如果接收方 IP 地址不是自己的地址,那一定是发生了什么错误。客户端计算机不负责对包进行转发,因此不应该收到不是发给自己的包(如果是服务器就不一定了。服务器的操作系统具备和路由器相同的包转发功能,当打开这一功能时,它就可以像路由器一样对包进行转发。在这种情况下,当收到不是自己的包的时候,就会像路由器一样执行包转发操作。
)。
当发生这样的错误时,IP 模块会通过 ICMP 消息将错误告知发送方。ICMP 规定了各种类型的消息。让我们遇到这个错误时,IP 模块会通过 Destination unreachable
消息通知对方。
主要的 ICMP 消息如下表所示:
消息 | 类型 | 含义 |
---|---|---|
Echo reply |
0 | 响应 Echo 消息 |
Destination unreachable |
3 | 出于某些原因包没有到达目的地而是被丢弃,则通过此消息通知发送方。可能的原因包括目标 IP 地址在路由表中不存在;目标端口号不存在对应的套接字;需要分片,但分片被禁用 |
Source quench |
4 | 当发送的包数量超过路由器的转发能力时,超过的部分会被丢弃,这是会通过这一消息通知发送方。但是,并不是说遇到这种情况一定会发这一消息。当路由器的性能不足时,可能连这条消息都不发送,就直接把多余的包丢弃了。当发送方收到这条消息时,必须降低发送速 |
Redirect |
5 | 当查询路由表后判断该包的入口和出口为同一个网络接口时,则表示这个包不需要该路由器转发,可以由发送方直接发送给下一个路由器。遇到这种情况时,路由器会发送这条消息,给出下一个路由器的 IP 地址,指示发送方直接发送过去 |
Echo |
8 | ping 命令发送的消息。收到这条消息的设备需返回一个 Echo reply 消息,以便确认通信对象是否存在 |
Time exceeded |
11 | 由于超过了 IP 头部中的 TTL 字段表示的存活时间而被路由器丢弃,此时路由器会向发送方发送这条消息 |
Parameter problem |
12 | 由于 IP 头部字段存在错误而被丢弃, 此时会向发送方发送这条消息 |
如果接收方 IP 地址正确,则这个包会被接受下来,这是还需要完成另外一项工作。IP 协议有一个叫做分片的功能,简单来说,网线和局域网中只能传送小包,因此需要将大的包切分成多个小包。如果接收到的包是经过分片的,那么 IP 模块会将它们还原成原始的包。
分片的包会在 IP 头部的标志字段中进行标记,当收到分片的包时,IP 模块会将其暂存在内部的内存空间中,然后等待 IP 头部中具有相同 ID 的包全部到达,这是因为同一个包的所有分片都具有相同的 ID。
此外,IP 头部还有一个分片偏移量(fragment offset)字段,它表示当前分片在整个包中所处的位置。
根据这些信息,在所有分片全部收到之后,就可以将它们还原成原始的包,这个操作叫做 分片重组。
到这里,IP 模块的工作就结束了,接下来包会被交给 TCP 模块。TCP 模块会根据 IP 头部中的接收方和发送方 I P地址,以及 TCP 头部中的接收方和发送方端口号来查找对应的套接字。找到对应的套接字之后,就可以根据套接字中记录的通信状态,执行相应的操作了。例如,如果包的内容是应用程序数据,则返回确认接收的包,并将数据放入缓冲区,等待应用程序来读取;如果是建立或断开连接的控制包,则返回相应的响应控制包,并告知应用程序建立和断开连接的操作状态。
参考文档
- 《网络是怎样连接的》—— 户根勤
往期文章
- 网络是怎样连接的(一)—— 浏览器访问 Web 服务器过程概览
- 网络是怎样连接的(二)—— 浏览器生成 HTTP 消息
- 网络是怎样连接的(三)—— 通过 DNS 服务器查询 IP 地址
- 网络是怎样连接的(四)—— DNS 服务器工作介绍
- 网络是怎样连接的(五)—— 委托操作系统进行收发消息过程概览
- 网络是怎样连接的(六)—— 协议栈内部探索步骤
- 网络是怎样连接的(七)—— 协议栈的内部结构
- 网络是怎样连接的(八)—— 探索套接字
- 网络是怎样连接的(九)—— 连接连的到底是啥
- 网络是怎样连接的(十)—— 连接操作的实际过程
- 网络是怎样连接的(十一)—— 协议栈发送数据特性
- 网络是怎样连接的(十二)—— 数据收发操作中重要标志位 ACK
- 网络是怎样连接的(十三)—— 从服务器断开并删除套接字
- 网络是怎样连接的(十四)—— 网络包传输概览(IP 模块视角)
- 网络是怎样连接的(十五)—— 网络包传输概览(IP 模块视角)
- 网络是怎样连接的(十六)—— 生成包含接收方 IP 地址的 IP 头部
- 网络是怎样连接的(十七)—— 生成以太网用的 MAC 头部