TCP/UDP协议深度解析(一):UDP特性与TCP确认应答以及重传机制
🔍 开发者资源导航 🔍 |
---|
🏷️ 博客主页: 个人主页 |
📚 专栏订阅: JavaEE全栈专栏 |
前言
在网络通信的世界里,传输层协议如同交通规则,决定了数据包如何从源头抵达目的地。其中UDP和TCP就像两个性格迥异的工程师:
🔹 UDP是"随性的自由派"——不建立连接、不做可靠性保证,却以极简的报文结构和低延迟,成为直播、游戏等实时应用的利器;
🔹 TCP则是"严谨的保守派",通过十大核心机制构建可靠性传输的"铜墙铁壁",但也付出了连接开销的代价。
本系列将带您深入TCP的精密设计,首期我们先从UDP的极简哲学切入,再重点解析TCP最基础的两个可靠性机制:
✅ 确认应答(ACK):每个数据包都有"电子回执"的奥秘
✅ 超时重传(RTO):动态计算的等待时间如何避免网络僵局
UDP
UDP(User Datagram Protocol,用户数据报协议)是传输层的核心协议之一,其设计目标是简单、高效、低延迟,适用于不需要可靠传输的场景。
UDP特性:无连接,不可靠传输,面向数据报以及全双工。
那么它为什么是不可靠的呢?我们先从UDP的结构说起。😇
UDP协议构成
- 源端口号 & 目的端口:五元组之一。
- 长度:载荷+头部的总大小。
- 校验和:用于检验数据是否出错。
UDP结构非常简单,由载荷和报头组成,报头存储了五元组以及长度校验和这些元素,但是它们的存储大小都仅有2字节,这也就导致了UDP长度的大小被限制在了0->65535之间,也就是64kb的大小。
UDP出现的时期较早,换做当时来看64kb或许绰绰有余,但是现在非常小了,而这也就导致了UDP的适用范围远没有TCP广泛。
那么当时如果传输大数据的时候有什么方案呢?🧐
1.应用层代码做拆包操作,一个大的应用层数据包拆成多个小的包,使用多个UDP数据报传输。❌缺点:工作量大,需要写大量的逻辑来实现分包组包功能,并且需要复杂的验证。
2.使用TCP协议,✅优点:没有数据包长度限制,原则上选简单,不容易出错的~
因此在传输较大的内容时,尽量避免使用UDP 。
校验和
校验和是UDP的数据检验机制,用于检验数据否发生变化,在信息传输过程中光信号、电信号、电磁波可能会受到外界的干扰,可能会让高低电平/光信号发生改变,这种现象我们称为“比特翻转”。😊
检验流程:
- 发送之前把整个数据包代入进去计算一遍校验和。
- 把校验和放入UDP数据报里面一起传输过去。
- 接收方收到后重新计算一下校验和,如果不一致直接丢弃。
UDP校验和运算比较简单,例如使用CRC方式进行校验(循环冗余校验)把每个字节(除了校验和位置的部分之外都当做一个整数当做累加,即使溢出也没关系,继续加最终结果,crc校验和。
如果数据到对端,数据出现错误,再次计算,就会和第一个校验和不一样。
⚠️极特殊情况:经过多次翻转后,校验和和数据反转后恰好一致(例如+1又-1)。
本来比特翻转就是小概率事件,如果恰好两个翻转抵消了影响,小之又小,因此我们可以忽略这种情况。
总结
上述内容基本涵盖了UDP的大多数机制,而它不可靠也是因为其简陋机制造成的:
- 不确认:UDP发送数据后,不会等待接收方的确认(ACK)。如果数据在传输中丢失(如网络拥塞、路由错误、校验和失败等),发送方无法感知,也不会重传。
- 不重传:即使检测到丢包(如通过应用层监控),UDP本身也不会自动重传数据。重传逻辑需由应用层自行实现(如QUIC协议在UDP上实现了重传)。
- 无顺序保证:UDP数据报可能因网络路径不同而乱序到达,但协议本身不会对数据包排序。接收方可能收到乱序数据,需应用层处理(如音视频流中的时间戳)。
TCP协议
TCP(Transmission Control Protocol,传输控制协议)是互联网核心协议之一,属于传输层,旨在提供可靠的、面向连接的数据传输服务。😎
TCP可靠传输的两个核心机制:确认应答,超时重传。
TCP协议构成
TCP协议在组成上要复杂的多。
- 源端口号 & 目的端口号:传输层的核心内容,属于五元组之一。
- 序号 & 确认序号:用于确认应答。
- 四位首部长度:长度指的是除了数据之外的长度,虽然取值是0-15,但是它的一个单位代表四个字节,不必担心不够用的情况。
- 保留部分:考虑到以后可能需要扩展,现在先不用提前占个位置。
- 六位标志位:代表TCP的一些特定功能。
- 窗口大小:用于滑动窗口的实现以及控制流量大小。
- 校验和:和UDP的校验和同样的作用,用于检验是否发生“比特翻转”。
- 选项:补充内容,可有可无。
确认应答
UDP的不可靠性之一就是没有确认对方是否收到的机制,如果过程中发生丢包的情况无法获知,而TCP在这方面可谓是下足了功夫👍。
TCP协议要求在发送信息后接收方要发送一个“应答报文”给发送方,如果发送方没有收到这个“应答报文”,则代表这个数据发生了丢包情况。
TCP的标记为ack为1就代表它是一个应答报文,应答报文不携带业务数据。
如果仅依靠这些机制会出现一种情况,如果你一次发送了好多信息,发送方如何知道那个收到了,那个没收到?😟
因此我们需要引入其他机制,而TCP的做法是给传输的数据进行编号。TCP连接建立时,发生方随机生成初始序列号,每次发送数据后:序列号按数据字节数递增。
在发送数据时发送一个序号,接收方发送ack确认报文的时候也会根据这个序号发送一个确认序号。
发送方在发送数据时将本次要发送字节流的第一个字节当做本次的序号,例如:1001-1008,本次序号为1001。
而接受方接收到数据后将本次接收到的字节流的结尾序号+1当做确认序号,例如:1001-1008,确认序号为1009。
确认序含义:该序号前面的序号都已经收到,接下来你从这个序号开始发送。
除此之外如果出现了后发先至的问题(由于网络路径不同导致的),接受方也可以根据接受到的序号来进行重新排序,确保应用层读到的数据顺序是正确的😆。
确认应答机制是TCP的丢包检验机制,仅有检验机制肯定是不行的,还需要有重传机制,下面我将介绍两种常见的重传机制。
快速重传
当 TCP 发生丢包(例如中间某个数据段丢失)但后续的新数据被成功接收时,接收方返回的 确认序号(ACK) 会 停留在最后一个按序接收的字节序号,而不会确认新数据(即使新数据已收到)。
而发送方收到 3 个重复的 ACK(即发送方连续收到对同一序号的确认),就会触发快速重传机制。
ack丢失情况
如果在数据传输过程中发生了ack丢失的情况,但是后续的ack却收到了,则会覆盖前面丢失的ack。
快速重传仅针对谁丢了,就重传谁,其他已经收到的数据无需重传,适用于少量丢包(如单个数据段丢失)。
超时重传
超时重传是 TCP 可靠性传输的核心机制之一,用于在数据包(或 ACK)丢失且无法通过快速重传(Fast Retransmit)恢复时,通过计时器触发数据包的重传。它的设计目标是在网络不可靠的情况下保证数据最终到达接收方。
如果发送方发送数据后,在 RTO(Retransmission Timeout)时间内没有收到任何对应的 ACK,那么就认为发生了严重的网络问题,发送方会将这些未收到ack的数据全部重新发送过去。
RTO 不是固定值,而是基于 RTT(Round-Trip Time,往返时间) 动态计算,如果发现超时后,会延长这个时间,延长达到一定次数后就会放弃此次传输。
在重发过程中,可能会出现接收方收到同一份数据的情况,接收方会对接受的数据进行去重操作。
下期预告
在 《TCP/UDP协议深度解析(二):TCP连接管理全解》 中,我们将深入探讨:
✅ 三次握手 的隐藏细节——为什么不是两次或四次?
✅ 四次挥手 的漫长告别——TIME_WAIT状态的真正意义