TCP 与 UDP 怎样传递数据

端口号确定后,数据还缺少一个关键问题:用什么方式传。TCP/IP 协议族中,传输层最重要的两个协议是 TCP(传输控制协议) 和 UDP(用户数据报协议)。

不同应用往往需要不同取舍:下载文件、打开网页时,一个字节的错误或丢失都可能造成文件损坏、页面错乱,因此需要可靠传输;而在线语音、实时游戏等场景,如果某个语音包丢了,几秒后再重传已经没有意义,此时低延迟比绝对可靠更重要,因此更适合轻量传输。

TCP:三次握手建立可靠连接

TCP 是一种面向连接、可靠、基于字节流的传输协议。双方正式发送业务数据之前,会先通过“三次握手”确认彼此可以正常收发包,并协商初始序列号。

客户端发送 SYN,服务器回复 SYN ACK,客户端再确认服务器的起始序号

  1. 第一次握手(SYN):客户端向服务器发送 SYN=1 的报文段,并随机选择一个初始序列号 seq=100,表示:“我想和你建立连接,我这边数据的起始编号是 100。”
  2. 第二次握手(SYN-ACK):服务器收到后回复 SYN=1, ACK=1。服务器随机选择自己的初始序列号 seq=700,并设置确认号 ack=101,表示:“我收到了你的请求,也同意建立连接;我这边数据从 700 开始,并且期待你的下一个字节编号是 101。”
  3. 第三次握手(ACK):客户端收到后回复 ACK=1,并设置 ack=701,表示:“我也收到了你的确认,连接可以建立。”

三次握手完成后,双方会在内核中分配连接资源,TCP 连接进入 ESTABLISHED 状态。之后,应用程序就可以通过这条连接传输数据。

序列号与确认号:TCP 如何保证不丢包

TCP 并不是简单地把数据发出去就结束,它会给每个字节编号。发送端把应用数据拆成多个 TCP 报文段,每个字节都有对应的序列号(Sequence Number),接收端通过确认号(Acknowledgment Number)告诉发送端:“我已经收到哪里了,接下来请从哪里开始发。”

例如,发送端连续发出序列号 401 到 406 的 6 个字节。接收端完整收到后,会回复一个 ACK 报文,确认号设置为 ack=407。

ack=407 的含义是:407 之前的字节我已经连续、完整地收到了,请从第 407 个字节开始发给我。

如果中途有数据包丢失:

接收端已连续收到:    字节 101 ~ 105
中途意外丢失:        字节 106 ~ 110(缺口!)
后续抢先到达:        字节 111 ~ 115

接收端虽然收到了 111~115,但中间缺少 106~110,所以确认号不能跳到 116,只能继续回复 ack=106。这种机制称为累积确认。收到但未交付给应用的乱序数据会先放入缓冲区,等待缺失部分补齐。

如果发送端长时间收不到 ack=106,就会判断该段数据可能丢失,并自动重传 106~110。只有缺口补齐后,接收端才会把完整数据按顺序交给上层应用。

中间字节缺失时,后面的字节先到也不能跳过缺口交付

计算下一次确认

练习

某次 TCP 传输的第一个数据字节序号为 401。接收端连续收到这次发送的 6 个数据字节,前面没有空缺,也没有 SYN 或 FIN。下一步应确认哪个序号?提交整数。

提交答案

题解 Hint

流量控制与拥塞控制:让发送速度更合理

TCP 不仅要保证数据不丢,还要保证发得出去、收得回来、网络也承受得住。这里涉及两类常见控制:

  • 流量控制(Flow Control):解决“接收端收得过来吗”的问题。如果接收端缓冲区压力大,或者应用读取数据变慢,它会在 ACK 报文中携带接收窗口(Window Size)。发送端看到这个窗口变小,就会少发数据;如果窗口为 0,发送端会暂停发送,直到接收端重新通知可用空间。这样可以避免把接收端缓冲区撑满。
  • 拥塞控制(Congestion Control):解决“网络链路扛得住吗”的问题。如果网络中路由器、交换机或带宽资源紧张,TCP 会通过慢启动、拥塞避免等算法降低发送速率,减少继续加剧网络拥堵的风险。

简单说,流量控制关心的是对端承受能力,拥塞控制关心的是网络路径承受能力。

四次挥手:正常关闭 TCP 连接

当双方通信结束,需要释放连接时,TCP 会经历四次挥手。因为 TCP 连接是全双工通信,每个方向都需要单独关闭,所以不能只靠一次请求就结束。

客户端 → 服务器:FIN    我这边的数据已经发完,准备关闭发送方向。
服务器 → 客户端:ACK    收到你的关闭请求。
服务器 → 客户端:FIN    我这边的数据也已经发完,准备关闭发送方向。
客户端 → 服务器:ACK    收到,连接彻底释放。

如果通信过程中出现异常,例如某台主机突然断电、进程崩溃,或者客户端连接了一个没有服务在监听的端口,系统内核通常会直接回复一个 RST(Reset) 报文,强制终止连接。

UDP:轻装上阵,但需要应用层自理

与 TCP 的复杂控制不同,UDP 是一种无连接、不可靠、面向报文的传输协议。

UDP 发送数据前不需要建立连接,没有三次握手,也没有序列号、确认应答、超时重传和拥塞控制。操作系统只需要在应用数据前面加上一个 8 字节的 UDP 头部,包含源端口、目的端口、长度和校验和,然后把数据包交给网络层发送。

这意味着,如果 UDP 数据包在网络中出现丢失、乱序、重复,UDP 本身不会负责修复。也正因为省去了握手和重传开销,UDP 延迟更低、开销更小。

常见适用场景包括:

  • DNS 查询:请求和响应通常都很短,一问一答即可。即使偶尔丢包,应用层可以简单重发。
  • 实时音视频、在线游戏:更看重低延迟,丢包时通常不会无限等待重传,而是通过抖动缓冲、插值、丢包补偿等应用层策略处理。
  • HTTP/3 与 QUIC:QUIC 基于 UDP 构建,但在上层重新实现了低连接建立延迟和可靠传输机制。