news 2026/10/3 2:25:01

TCP 与 UDP:从可靠字节流到无连接数据报,怎么选、怎么测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TCP 与 UDP:从可靠字节流到无连接数据报,怎么选、怎么测

TCP 与 UDP:从可靠字节流到无连接数据报,怎么选、怎么测

ℹ️ 读者定位

适合你,如果:会调用 API、配置端口、写 Socket 服务,或者正在学习计算机网络,但还分不清 TCP 的可靠性、UDP 的消息边界和 QUIC 的关系。

开始前需要:知道 IP、端口、客户端和服务器;不要求先读完 TCP 状态机或内核源码。

读完可以完成:解释 TCP 三次握手、四次挥手、序列号、重传、窗口和粘包;解释 UDP 的边界与风险,并按场景选择 TCP、UDP 或基于 UDP 的协议。

暂时不适合:想看 TCP 拥塞控制算法的数学推导、Linux 内核源码或生产级自定义可靠传输协议设计;本文先建立工程判断能力。

在工作中,我们经常会看到这样的争论:文件传输用 TCP,音视频用 UDP;TCP 可靠但慢,UDP 快但不可靠。这个说法有一点道理,但拿来直接做架构决策就太粗了。

先给结论:TCP 把应用数据交付成可靠、有序的字节流;UDP 发送一个个独立数据报,尽量少替应用做决定。

真正选型时,先问四个问题:

  1. 数据丢一部分,业务还能不能继续?
  2. 数据顺序重要吗?旧数据晚到还有价值吗?
  3. 应用需要保留消息边界,还是只需要连续字节流?
  4. 重传、拥塞控制和安全能力,准备交给谁负责?

这篇内容分为以下几个部分:

  1. 先建立 TCP 与 UDP 的准确直觉。
  2. 拆开 TCP 的连接、可靠传输和关闭过程。
  3. 看懂 UDP 做了什么、没有做什么。
  4. 用最小命令观察两种协议。
  5. 通过场景表和 QUIC 关系完成选型。

一、先把 TCP 和 UDP 放回传输层

1.1 TCP 与 UDP 分别交付什么

TCP(Transmission Control Protocol,传输控制协议)向应用提供的是可靠、有序的字节流。

UDP(User Datagram Protocol,用户数据报协议)向应用提供的是独立的数据报。一个数据报可以理解成一条带边界的消息,但它可能丢失、重复、乱序,协议本身不负责像 TCP 那样补齐这些能力。

TCP:应用写入 A + B + C 接收端读到一条连续字节流:A+B+C UDP:应用发送[A][B][C]接收端按一个个数据报读取:可能收到[A]、[C],也可能丢掉[B]

RFC 9293 将 TCP 定义为面向可靠通信的传输协议;RFC 768 则将 UDP 定义为最小机制的数据报协议。这两个定位,决定了后面所有差异。

1.2 四个维度比“快不快”更重要

维度TCPUDP
连接面向连接,需要建立和维护状态无连接,不需要 TCP 式连接建立
交付可靠、有序、去重后的字节流尽力交付的数据报,可能丢失、重复、乱序
消息边界不保留应用的消息边界保留数据报边界
控制能力TCP 负责确认、重传、窗口和拥塞控制应用或上层协议自行决定是否补这些能力

这里一定要注意:TCP 的“可靠”不是“业务一定成功”。它只负责把连接中的字节尽力可靠地交给对端 TCP;服务器崩溃、应用超时、权限失败,TCP 都不能替业务解决。

1.3 为什么说 TCP 是字节流

假设发送端连续调用三次:

send("登录");send("用户A");send("密码B");

接收端不一定按三次send对应的边界读取。它可能一次读到全部内容,也可能先读到“登录用户”,再读到“A密码B”。这就是通常所说的 TCP 粘包 / 拆包现象。

它不是 TCP 出错,而是 TCP 根本没有承诺“保留应用层消息边界”。应用协议需要自己设计长度字段、分隔符、固定长度或其他 framing 规则。

消息格式示例:|长度|消息体|↓ 先读长度,再按长度读取消息体

1.4 UDP 的消息边界也不是可靠性保证

UDP 一次sendto通常对应接收端的一次数据报读取,这让实时音视频、状态同步和简单查询更容易按消息处理。

但边界保留不代表消息一定到达。UDP 仍可能遇到:

  • 网络拥塞导致数据报被丢弃;
  • 无线网络或路径变化导致乱序;
  • 应用重复发送导致重复数据;
  • 数据报过大导致分片、丢包概率增加或被中间设备丢弃。

如果业务不能接受这些情况,就需要在 UDP 之上增加序列号、确认、重传、过期时间、拥塞控制和加密等机制,或者直接选择一个已经提供这些能力的上层协议。


TCP 与 UDP 的能力边界

二、TCP:连接、可靠传输和关闭

2.1 TCP 三次握手在确认什么

TCP 三次握手不是“为了显得复杂”,它要让双方确认彼此的发送与接收能力,并同步初始序列号,建立连接状态。

客户端 服务器|---- SYN ---------------->|请求建立连接,带初始序列号|<--- SYN + ACK -----------|确认客户端,并发送自己的序列号|---- ACK ---------------->|确认服务器的序列号

三次握手完成后,连接进入ESTABLISHED状态,应用数据才会稳定地通过这条 TCP 连接传输。

为什么不能只握手两次?因为服务器需要知道客户端确实收到了自己的初始序列号和确认;第三个ACK让双方对连接建立结果达成一致,也能减少历史重复 SYN 造成的错误连接状态。

这三个报文只属于 TCP。UDP 没有 TCP 式三次握手;如果某个 UDP 应用需要握手,那是应用协议自己设计的。

2.2 序列号、ACK 和重传怎样配合

TCP 给字节编号。发送端把一段数据发出去,接收端通过 ACK 告诉发送端“我已经按序收到哪里,下一步希望收到哪个序号”。

发送端:数据序号1000,长度500接收端:ACK1500,表示下一个期望的字节是1500

如果发送端在超时时间内没有得到确认,或者通过重复 ACK 等现象判断可能丢包,就会触发重传或快速恢复机制。实际 TCP 实现还会结合接收窗口、往返时延和拥塞控制调整发送行为。

因此,TCP 可靠性不是一次性“发出去就完事”,而是发送、确认、判断、重传和排序共同完成的。

2.3 流量控制和拥塞控制不是一回事

这两个概念很容易混在一起:

机制主要回答的问题关注对象
流量控制接收端来不来得及收?接收端缓冲区,通常体现为接收窗口
拥塞控制网络中间路径能不能承受?网络链路和路由路径的拥塞程度

接收端处理慢时,TCP 可以通过窗口告诉发送端先别发太快;网络拥塞时,TCP 还要降低发送速率,避免大量连接把网络拖入拥塞崩溃。

TCP 的可靠性和“慢”不能简单画等号。真实吞吐量还受带宽、往返时延、丢包、窗口、拥塞算法、系统参数和应用读写速度影响。

2.4 TCP 四次挥手在关闭什么

TCP 是全双工连接。客户端和服务器的发送方向可以分别关闭,所以典型关闭过程是四个报文:

客户端 服务器|---- FIN ---------------->|客户端没有更多数据发送|<--- ACK -----------------|服务器确认收到|<--- FIN -----------------|服务器也没有更多数据发送|---- ACK ---------------->|客户端确认收到

为什么不是三次?因为服务器收到客户端的FIN后,可能还有剩余数据没有发送完。它可以先回 ACK,等数据处理完成后再独立发送自己的 FIN。

实际抓包不一定永远是教科书里的四个报文:双方同时关闭、连接异常、发送 RST、重传或中间设备行为,都会让时序出现变化。但理解“两个方向分别关闭”是关键。

主动关闭的一方通常还会进入TIME_WAIT,等待一段时间,避免旧连接中的延迟报文影响后续使用相同四元组的新连接。服务端看到大量TIME_WAIT不要立即下结论,需要结合谁主动关闭、连接频率和系统参数分析。


TCP 三次握手、数据传输与四次挥手

三、UDP:少做一点,把控制权交给应用

3.1 UDP 首部为什么看起来很短

UDP 首部只包含源端口、目的端口、长度和校验和等基本信息,协议本身不维护 TCP 那样的连接状态、序列号窗口和确认重传流程。

这带来几个直接结果:

  • 不需要 TCP 三次握手才能发送第一份数据报。
  • 没有 TCP 式连接关闭过程。
  • 不会因为等待某个丢失数据报而自动补齐有序字节流。
  • 应用可以按自己的业务语义处理过期、丢失和重复。

省掉机制不等于凭空获得性能。UDP 应用如果自己补齐可靠性,最终仍然要承担协议设计、状态维护、重传和拥塞控制的成本。

3.2 什么场景可以接受丢包

实时系统往往更关心“现在的数据是否新鲜”,而不是“历史每一帧是否完整到达”。例如视频通话中,一帧画面晚到 500 毫秒,补回来也可能没有意义;此时丢掉旧帧、继续播放新帧,体验可能更好。

常见做法包括:

  • 每个数据报带序列号和时间戳;
  • 接收端设置抖动缓冲,平衡乱序和延迟;
  • 对关键帧、控制消息使用确认或重传;
  • 对普通状态更新只保留最新值;
  • 使用前向纠错或冗余,减少少量丢包的影响。

这些能力通常来自 RTP、游戏协议、实时通信框架或自定义应用层协议,不是 UDP 首部自动提供的。

3.3 UDP 也不能无视拥塞和安全

UDP 不提供 TCP 式拥塞控制,并不意味着应用可以无限速发送。一个不控制速率的 UDP 程序可能压垮自己、局域网或共享链路。

生产环境使用 UDP 时,至少要考虑:

  • 报文大小,避免不必要的 IP 分片;
  • 发送速率和拥塞反馈;
  • 重放、伪造、放大攻击和反射攻击;
  • 身份认证、完整性保护和必要的加密;
  • NAT、状态防火墙和 UDP 可达性。

这里一定要注意:UDP 简单的是传输层,不代表基于 UDP 的生产协议可以简单到不做安全设计。

四、用最小实验观察两种协议

4.1 先查看本机 TCP 状态

Windows PowerShell:

Get-NetTCPConnection|Sort-Object State, RemotePort|Select-Object-First20

Linux:

ss-tanp

你可以重点看:

  • LISTEN:服务端正在监听;
  • ESTABLISHED:连接已经建立;
  • TIME_WAIT:主动关闭的一方等待旧报文消失;
  • SYN_SENT/SYN_RECEIVED:连接还在建立过程中。

☑️ 实际效果图 / GIF 待补充:查看 TCP 连接状态

请补充真实终端截图,展示一个监听端口、一个已建立连接或TIME_WAIT状态;注意隐藏公网 IP、用户名和敏感端口。

建议文件名:截图资源/03-tcp-连接状态.png。

4.2 用 netcat 做最小 TCP 实验

在接收端执行:

nc-l9000

在发送端执行:

nc<接收端地址>9000

输入文本后,接收端会看到内容。这个实验的重点不是搭建生产服务,而是观察 TCP 先建立连接、再传输字节流的过程。

不同系统的 netcat 参数可能不同。Windows、Linux 和 macOS 上如果-l行为不一致,先执行nc -h,按本机版本调整。

4.3 用 netcat 做最小 UDP 实验

接收端:

nc-u-l9001

发送端:

nc-u<接收端地址>9001

UDP 实验可能看起来更“直接”:没有 TCP 三次握手,发送端就可以发数据报。但这不代表对端一定收到,也不代表接收端能确认消息没有重复或乱序。

☑️ 实际效果图 / GIF 待补充:TCP 与 UDP netcat 实验

请补充两个终端的真实截图或 GIF,展示 TCP 连接建立后传输,以及 UDP 直接发送数据报的对比;不要把概念图当成实验结果。

建议文件名:截图资源/04-tcp-udp-netcat.png。

4.4 用抓包验证握手和数据报

Linux 可以使用:

sudotcpdump-niany'tcp port 9000 or udp port 9001'

Wireshark 可以使用过滤器:

tcp.port==9000||udp.port==9001

TCP 抓包重点看 SYN、SYN/ACK、ACK、序列号、确认号和 FIN;UDP 抓包重点看每个数据报的长度、源/目的端口以及是否出现间隔或丢失。

这里的“应该看到什么”是协议层面的观察目标,不是固定输出。网卡、系统、工具版本和网络路径都会影响抓包细节。

五、场景选择:到底该用 TCP 还是 UDP

5.1 一张实用选型表

场景常见选择为什么需要补充关注
文件传输、数据库、网页、普通 APITCP丢失或乱序的数据通常不能直接交给业务连接复用、超时、拥塞和服务端容量
DNS 查询UDP 常见单次消息短,减少连接状态和等待截断、重试、TCP / DoT / DoH 等替代路径
实时音视频UDP / RTP 常见过期数据可能不值得重传编解码、抖动缓冲、拥塞控制、安全
在线游戏状态同步UDP 或基于 UDP 的协议可以按新旧状态决定丢弃与补偿可靠控制消息、反作弊、限速
设备发现、局域网广播UDP 常见适合一次发送、多个设备接收广播范围、重复、认证和网络隔离
HTTP/3QUIC over UDPQUIC 提供连接、流、可靠性和 TLSUDP 可达性、代理、防火墙和回退

不要只看应用名字。比如“聊天”可能包含消息发送、在线状态、文件传输和音视频四条链路,每条链路的协议选择可以不同。

5.2 QUIC 为什么基于 UDP

QUIC 使用 UDP 作为底层封装,但它不是“裸 UDP”。RFC 9000 描述的 QUIC 自己提供了连接、流、流量控制、拥塞控制、丢包检测和路径迁移,并把 TLS 握手集成到连接建立过程中。

因此可以这样理解:

传统 Web:HTTP/1.1 或 HTTP/2 → TLS → TCP → IP 现代 Web:HTTP/3 → QUIC(包含 TLS 与可靠流)→ UDP → IP

QUIC 之所以基于 UDP,是为了让上层传输协议拥有更大的演进空间,避免被操作系统内核中固定的 TCP 行为完全限制。但它仍然要面对网络丢包、拥塞和 UDP 被拦截等现实问题。

5.3 一个简单的决策顺序

如果你在做新协议或新服务,可以按这个顺序判断:

  1. 数据是否必须完整、有序到达?是的话,先考虑 TCP 或可靠的上层协议。
  2. 数据是否有明确消息边界?有的话,UDP 或在 TCP 上设计 framing 都可以;不要误以为 TCP 自动保留边界。
  3. 旧数据晚到是否仍有价值?没价值时,UDP / QUIC 流或实时协议可能更适合,但要补齐控制与安全。
  4. 你是否有能力维护可靠性、拥塞控制和安全?没有的话,优先使用成熟协议,不要从裸 UDP 开始造轮子。

六、常见误区与最后记忆点

6.1 常见误区

  • TCP 一定比 UDP 慢。TCP 的握手、确认和控制会带来机制成本,但实际性能取决于网络、实现、数据量和应用需求。
  • UDP 没有连接,所以不需要状态。UDP 没有 TCP 式连接状态,但应用完全可以自己维护会话、序列号和认证状态。
  • UDP 丢包就不能用。实时媒体和状态同步可以按业务容忍丢失、过期和乱序,但必须明确补偿策略。
  • TCP 粘包是网络故障。TCP 是字节流,应用需要自己设计消息 framing。
  • QUIC 就是 UDP 加 TLS。QUIC 还提供流、可靠传输、拥塞控制、连接 ID 和路径迁移等传输能力。
  • 三次握手和四次挥手适用于所有协议。它们是 TCP 的连接建立与关闭过程,不是 UDP 的固定流程。

6.2 最后记住这句话

TCP:我帮你把字节可靠、有序地送到对端,但不保留消息边界。 UDP:我帮你发出一个个数据报,消息边界在,但可靠性要你自己决定。 QUIC:我在 UDP 上重新提供现代传输能力,并集成 TLS。

工程上不要先问“哪个更快”,而要先问:数据能不能丢、顺序重不重要、边界谁负责、控制机制谁维护。

参考资料

  • RFC 9293 - Transmission Control Protocol
  • RFC 768 - User Datagram Protocol
  • RFC 8095 - Services Provided by IETF Transport Protocols
  • RFC 9000 - QUIC
  • RFC 3550 - RTP
  • RFC 8085 - UDP Usage Guidelines
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 2:23:55

好问题从哪里来:一场关于“发现“本身的深度追问

有一类人,总能在一个领域里问出让所有内行都愣住的问题。他们不一定比别人聪明,不一定读书比别人多,甚至不一定是那个领域里技术最扎实的人。但他们总能在别人司空见惯、习以为常的地方,精准地指出一个裂缝——一个此前没有人意识到需要被解释的东西。 这种能力常被简单归结为…

作者头像 李华
网站建设 2026/10/3 2:18:35

Tool Graph Retriever: Exploring Dependency Graph-based Tool Retrieval for Large Language Models

文章主要内容和创新点 主要内容 本文针对大型语言模型(LLM)驱动的AI代理在工具检索中存在的问题,提出了一种名为Tool Graph Retriever(TGR,工具图检索器) 的方法。 背景:随着AI代理配备的工具数量激增,受限于模型上下文长度,需通过检索筛选工具。现有方法主要依赖用…

作者头像 李华