
计算机网络 CS144 - 第二单元 - 传输层
TCP 服务模型(TCP Service Model)
工作流程
- 应用层想要传输数据,于是调用 TCP 层并传递想要传输的数据
- TCP 将拿到的数据放入 TCP 段中,然后将 TCP 段传递给 IP 层(网络层)
- IP 层将拿到的数据封装为一个 IP 数据报并添加 IP 地址,然后将 IP 数据报传递给链路层
- 链路层构建链路帧,并添加链路地址(比如以太网地址),然后将其发送到网络中
双向连接的建立——三次握手
要建立双向连接,需要经过以下流程:
- A 向 B 发送 Syn 信息表示请求 A 到 B 的连接
- B 向 A 发送 Ack 信息表示同意 A 到 B 的连接,同时附带 Syn 信息表示请求 B 到 A 的连接
- A 向 B 发送 Ack 信息表示同意 B 到 A 的连接
同时两端会各自维护一个状态机,后面会讲到
双向连接的断开——四次挥手
要断开双向连接,需要经过以下流程:
- A 向 B 发送 Fin 信息,表示想要断开 A 到 B 的连接
- B 向 A 发送 Ack 信息,表示同意断开 A 到 B 的连接,同时可能附带还未发送完的数据
- 一段时间后,B 完成了所有需要发给 A 的数据的发送,向 A 发送 Fin 信息,表示想要断开 B 到 A 的连接
- A 向 B 发送 Ack 信息,表示同意断开 B 到 A 的连接
TCP 为应用层提供的服务
- TCP 保证数据会到达,如果传输中断,TCP 会重新发送
- TCP 通过以下方式保证传输是可靠的:
- 当 TCP 接收到数据时,会发送一个确认包给发送方,表示数据正确到达
- 使用校验和来检测数据是否损坏
- 使用序列号用于检测数据是否丢失(每个数据段头部会有一个序列号)
- 流量控制来防止接收方过载:接收方会不断告知发送方是否可以继续发送,即告诉发送方缓冲区中还有多少空间可以接收新数据
- TCP 会保证给应用层的数据是符合顺序的,即如果接收到的数据是乱序的,TCP 会使用序列号将数据重新排序
- TCP 会试图在所有使用网络的 TCP 连接之间平均分配网络容量(拥塞控制机制)
TCP 段内部格式
- Destination Port:目标端口说明数据应该传输给接收方的哪一个应用(比如 SSH 服务就是 22 端口)
- Source Port:源端口说明接收方应该使用哪个端口发送回数据(即接收方将发送方的源端口作为自己的目标端口)
- Sequence:序列号表示 TCP 数据字段中第一个字节在字节流中的位置
- Acknowledgement Sequence:
确认序列号告诉另一端期望接收的下一个字节号,同时这也表明了该字节号前的所有字节数据均被成功接收 - Checksum:校验和是根据整个头部和数据计算得到的,用于帮助接收方确认数据是否损坏
- HLEN:说明 TCP 字段的头部长度为多少
- TCP options:可选字段包含了 TCP 标准建立后新添加的头部字段,HLEN 也说明了有多少可选字段存在(通常是没有的)
- Flags:
- ACK:表明确认序列号是有效的,确认了之前接收到的所有数据
- SYN:表明正在发送同步信号,即三次握手中的一部分
- FIN:表示关闭单方向的连接
- PSH:表示数据到达时,对方 TCP 端应该立即交付数据给应用层(这对一些时间敏感的操作很有用,比如按键操作)
TCP 连接的唯一标识
图中的五个字段组成了 TCP 连接的唯一标识:
IPv4 头部字段中的 IP DA 和 IP SA 指定了两台机器在网络中的位置,Protocol ID 指定了传输层使用的协议为 TCP
TCP 头部字段中的 Source Port 和 Destination Port 指定了两台机器中的指定应用
然而,这样的唯一标识只有在下述条件成立时才有效:连接的两端使用唯一的源端口用于 TCP 服务。
比如主机 A 使用 20 端口用于与 B 的一个连接服务,再选择 20 端口用于另一个连接服务就会导致错误。
一般采用一个简单的方法来避免这种情况:对于每一个新增的连接,使用递增的源端口号。
但是这样做也有可能会导致错误,比如主机 A 突然新增了大量的到主机 B 的连接,端口的递增可能会超出位数限制从而绕回到一个已经使用的端口。
使用同一个端口用于两个服务,会导致接收数据的混淆。
序列号的作用
为了减少混淆的可能性,TCP 连接会在初始化时使用一个随机的序列号来引用字节流中的字节(这并不是万无一失的,但是确实减少了混淆的可能性)
由于初始化序列号的存在,三次握手时会附带相关数据,即图中的 ISN(Initial Sequence Number):
序列号在 TCP 中的工作如图:
UDP 服务模型(UDP Service Model)
UDP 段内部格式
- Checksum:校验和的使用是可选的,如果不使用,则为全零;如果使用,校验和的计算会包含 UDP 头部和数据、IPv4 头部的起止地址和UDP协议 ID(这违反了层次的清晰分离原则,但是这使得 UDP 层能够检测到被错误投递的数据报)
- Length:至少为 8 字节,因为这是 UDP 头部的长度
UDP 的三个特性
- 无连接的数据报服务:数据的传输不需要建立连接,且数据包可能乱序到达,也可能丢失
- 自包含的数据报:即每个数据报包含足够多的信息,可以被独立传输、处理
- 不可靠传输:无确认、无丢包检测、无流量控制
总的来说,UDP 提供了一种更简单的数据报传输服务
ICMP 服务模型(ICMP Service Model)
ICMP 的工作
ICMP 位于传输层,用于向网络层传递错误信息
以下为几个错误信息的示例
ping
命令是怎么使用 ICMP 的?
ping
用于测试另一台主机的活跃状态,比如在终端中运行下面这行命令
1 | ping bilibili.com |
便可以看到类似下面的信息
1 | Pinging bilibili.com [198.18.0.16] with 32 bytes of data: |
其中的过程如图,ping 直接调用 ICMP,发送一个 ICMP 回显请求,然后接收方返回一个回显应答
总结
- ICMP 提供了网络层到终端主机和路由器的信息
- ICMP 位于网络层上方,所以属于传输层,但是 ICMP 是为网络层服务的
ping
和traceroute
等命令都依赖于 ICMP
端到端原则(End to End Principle)
在主机 A 到主机 B 的连接中,网络其实可以做很多事情来进行优化,比如压缩数据、重新格式化或者优化请求、添加安全措施等等,但是通常来说,网路并没有怎么做,这是为什么?因为要遵循 端到端原则。
端到端原则的来源
之所以会有端到端原则,是因为以下这样一个例子:
文件从源主机到目标主机,每两个机器之间的链路都有错误检测。
理想状况是,传输中出现错误,检测到错误,拒收文件然后重新发送。
但是问题在于链路上的错误检测只能检测传输层面的错误,如果出现内存层面的错误就无法检测了,如图
确保文件正确到达的唯一方法就是进行端到端的检查。
端到端功能之外的优化
考虑无线链路和有线链路的可靠性,有线链路的传输往往是极其可靠的,而无线链路的传输则并没有那么可靠。
链路层的重传机制可以通过有效地检测和纠正错误、减少丢包、提高数据的可靠性,极大地优化无线链路的性能。
错误检测(Error Detection)
错误检测 有三种方法:
- Checksum(校验和)
- CRC(循环冗余校验码,cyclic redundancy code)
- MAC(消息认证码,message authenciation code)
Ethernet 会在尾部增添一个 CRC,TLS 在尾部增添一个 MAC
IP 则在数据头部增添一个 Checksum
三种错误检测方法,各有优劣
Checksum
Checksum 是一种简单的错误检测方法,它通过对数据内容进行求和(通常是按字节、按块或按固定长度的单位)得到一个和校验值。然后,发送端和接收端都计算并比较这个校验和值,以判断数据是否在传输过程中发生了错误。
- 优点:实现简单,计算量小,计算速度快
- 缺点:鲁棒性低,无法检测偶数个比特位的错误以及其他的特定错误
Checksum 主要用于简单的数据完整性检测,例如传输协议(如IP、TCP、UDP)或存储系统中的错误检测。
CRC
CRC 是一种比 Checksum 更强大的错误检测方法,它基于多项式除法。数据被看作一个大的二进制数,使用一个预定的“生成多项式”进行除法运算。除法的余数(也叫 CRC 校验码)就是要附加到数据中的校验值。
- 优点:鲁棒性高,错误检测能力强
- 缺点:实现复杂,计算成本高
CRC 被广泛应用于通信系统(如以太网、硬盘、CD/DVD)以及文件压缩和存储,例如在磁带存储中检测传输错误,或在互联网传输过程中检测数据完整性。
MAC
MAC 是一种结合了加密和哈希的检测方法,除了用于验证数据的完整性外,还能验证数据的身份(即消息的真实性)。MAC 使用一个密钥和一个哈希算法(如HMAC)对消息进行加密处理,生成一个短小的“验证码”。只有知道密钥的双方才能生成和验证该验证码。但是,MAC 无法检测任何内容上的错误!
- 优点:不仅保证数据未被篡改,还能够验证数据的来源,抗篡改性强
- 缺点:计算成本较高,依赖于同一个共享密钥,无法检测到内容的错误
MAC 被广泛应用于加密通信协议(如SSL/TLS)、身份验证、数字签名和支付系统中,确保数据的安全性和完整性。
有限状态机(Finite State Machines)
有限状态机是一个状态转换模型,它包括:
- 状态(State):系统可能处于的不同阶段。
- 事件(Event):系统状态转移的触发因素,可以是输入的外部信号或某些条件的变化。
- 状态转移(Transition):从一个状态到另一个状态的变化过程。
- 动作(Action):在状态转移时执行的操作,如发送数据包、接收数据等。
流量控制(Flow Control)
问题在于,如果主机 A 以每秒 500,000 个数据包的速度发送,但是 主机 B 只能每秒接收 200,000 个数据包,这就会导致多余的数据包被丢弃。
如今大多数协议中使用两种方法
- Stop and Wait
- Sliding Window
停止-等待(Stop and Wait)
- 发送方一次只发送一个数据包
- 每当接收到数据时,接收方发送确认信息(ACK)
- 发送方接收到确认信息时发送下一个数据包
- 若超时为收到确认信息,发送方重新发送数据
- 使用一位计数器来检测是否是重复的数据
滑动窗口(Sliding Window)
每个数据段都有一个序列号(SeqNo),用于确保数据包被正确接收、乱序回复、丢包检测等
发送方的工作机制
-
维护以下三个变量:
-
发送窗口大小(Send Window Size, SWS):
表示当前允许发送但尚未收到确认的最大数据段数,发送窗口的大小决定了 TCP 连接的流量控制能力 -
最后一个已确认的数据段(Last Acknowledgment Received, LAR):
这是发送方收到的 ACK 号,即 所有比它小的序列号的数据都已经成功到达接收方 -
最后一个已发送的数据段(Last Segment Sent, LSS):
这是当前发送方已经发送的 最大序列号
-
-
维护不等式:
-
接收新的 ACK 后,推进
,腾出窗口空间,发送新数据 -
使用缓存存储未确认的数据,提高数据传输效率
接收方的工作机制
- 维护三个变量
- 接收窗口大小(Receive Window Size,RWS)
- 最大可接受的序列号(Last Acceptable Segment,LAS)
- 最后一个成功接收并按序存储的段(Last Segment Received,LSR)
- 维护不等式:
- 发送 ACK:接收方使用 累积确认(Cumulative ACKs),即只确认到最后一个连续的段,比如接收到
1, 2, 3, 5
则会发送ACK 4
(TCP ACK 指的是 “下一个期望的数据”,即ACK = 4
表示 “请发送 4”)
可靠传输(Reliable Connection)
重传策略(Retransmission Strategies)
针对滑动窗口的重传策略如下
发送方发送数据时,启动一个定时器,若 ACK 超时,则会重传数据
重传策略有两种,回退重传 和 选择重传
回退重传
重传当前窗口的所有数据
- 优点:实现简单,适合高丢包率的环境(当大量数据丢失时,恢复速度更快)
- 缺点:浪费带宽,不适合高吞吐量的环境
选择重传
只重传 ACK 超时的数据包
- 优点:提高带宽利用率,更适应网络抖动
- 缺点:接收端复杂度更高,需要额外的缓冲区
TCP 连接和断开(TCP Setup and Teardown)
三次握手
步骤 | 客户端 © | 服务器 (S) | 关键字段 | 说明 |
---|---|---|---|---|
SYN | SEQ=X |
- | SYN=1, ACK=0 |
客户端请求连接 |
SYN-ACK | - | SEQ=Y, ACK=X+1 |
SYN=1, ACK=1 |
服务器确认并发送 SYN |
ACK | SEQ=X+1, ACK=Y+1 |
- | ACK=1 |
客户端确认,连接建立 |
TCP 还支持另一种连接方式,称为 同时打开(Simultaneous Open)
两方同时发送 SYN 然后一同发送 SYN+ACK,这需要四条消息而不是三次握手的三条
四次挥手
步骤 | 发送方 | 接收方 | 关键标志位 | 作用 |
---|---|---|---|---|
FIN | 客户端 → 服务器 | FIN=1, ACK=1 |
客户端请求断开 | |
ACK | 服务器 → 客户端 | ACK=1 |
服务器确认 FIN | |
FIN | 服务器 → 客户端 | FIN=1, ACK=1 |
服务器也准备断开 | |
ACK | 客户端 → 服务器 | ACK=1 |
客户端确认 FIN,进入 TIME_WAIT |
关于 TIME_WAIT
在客户端发送 最后一个 ACK 之后,会进入 TIME_WAIT 状态,持续 2 倍最大报文段生存时间(2MSL, Maximum Segment Lifetime)。这样做的目的如下:
确保服务器收到了 ACK:
如果最后的 ACK 丢失,服务器会重新发送 FIN,客户端可以重新 ACK。防止旧连接影响新连接:
旧的 TCP 连接可能会有延迟的数据包,TIME_WAIT 确保它们都被丢弃。
总结
在计算机网络中,传输层协议的设计至关重要,它直接影响数据在网络中的传输方式与可靠性。TCP、UDP 和 ICMP 各自提供了不同的通信模型,适用于不同的应用需求。
- TCP 服务模型(TCP Service Model) 采用连接导向的通信方式,提供可靠的数据传输、流量控制和拥塞控制,确保数据的顺序性和完整性。它适用于对数据可靠性要求较高的应用,如网页浏览(HTTP/HTTPS)和文件传输(FTP)。
- UDP 服务模型(UDP Service Model) 采用无连接的通信方式,不保证数据可靠性、顺序性和完整性,但具有低延迟、高吞吐的优点,适用于实时音视频通信(如 VoIP、在线游戏)等应用。
- ICMP 服务模型(ICMP Service Model) 主要用于网络诊断和错误报告,帮助主机和路由器报告网络问题,如
ping
和traceroute
。
在传输过程中,端到端原则(End-to-End Principle)强调应在通信的终端系统(如应用层)实现可靠性,而非依赖网络中的中间节点。
错误检测(Error Detection)机制(如 TCP 校验和、UDP 校验和和 ICMP 误码报告)在数据传输中起到了关键作用,确保数据完整性。
有限状态机(Finite State Machines, FSM)是 TCP 连接管理的核心,定义了从连接建立(三次握手)到连接终止(四次挥手)的完整状态转换过程。流量控制(Flow Control)机制,如 TCP 的滑动窗口协议,确保发送方不会发送超过接收方缓存能力的数据,防止接收端溢出。
可靠传输(Reliable Connection)是 TCP 的核心特性之一,它通过 ACK 机制、超时重传、滑动窗口、拥塞控制(如 AIMD、慢启动) 来确保数据的正确、完整、有序传输。在不同网络条件下,TCP 还能动态调整其发送策略,以提高传输效率和网络利用率。
综合来看,计算机网络协议的设计在可靠性、性能和复杂性之间做出了权衡,不同的应用场景需要选择合适的传输方式,以实现最优的通信效果。