UDP 与 TCP¶
传输层首先解决复用¶
同一主机可能同时运行浏览器、SSH 和 DNS 客户端。IP 地址只定位到主机接口,端口号进一步标识通信端点。操作系统依据目的 IP、目的端口、源信息和传输协议,把到达的数据交给匹配的 Socket。
客户端常使用临时端口,服务器监听约定或配置端口。例如浏览器可能从 192.0.2.10:53124 连接 198.51.100.20:443。端口 443 并不“属于 HTTPS”到不可改变,它只是默认约定;应用仍可在其他端口运行,也可能在 443 上承载非预期协议。
UDP:保留消息边界的最小服务¶
UDP 首部很小,主要包含源端口、目的端口、长度和校验和。它提供:
- 面向数据报,一次发送对应一个独立消息边界。
- 无连接握手,发送前不建立可靠状态。
- 尽力交付,不保证到达、顺序或唯一性。
- 校验可检测传输中的部分比特错误,但检测到错误通常直接丢弃。
最小例子:客户端连续发送 A、B 两个 UDP 数据报,服务端可能看到 A,B,也可能只看到一个、顺序颠倒,甚至看到应用重试造成的重复。若业务不能接受这些结果,应用必须增加序号、确认、重试、去重或前向纠错。
UDP 适合一次请求—响应、应用自定义可靠性、实时媒体和组播等场景。DNS 常用 UDP 完成小查询;实时音视频通常更在意“及时”而非“迟到但完整”;QUIC 借 UDP 穿过现有网络设备,并在用户态实现更丰富机制。
TCP:可靠有序字节流¶
TCP 的核心服务是两进程之间的全双工、有序、可靠字节流。它没有应用消息边界:发送方两次调用 send,接收方可能一次 recv 读完,也可能分多次读到。应用协议必须自行规定消息长度或分隔方式。
TCP 连接建立通常使用三次握手:
握手的动机不只是“打招呼”,还要让双方确认双向可达、同步序号并协商选项。仅两次消息时,服务器难以确认客户端是否已收到自己的序号与参数。
连接关闭通常每个方向独立发送 FIN,因此半关闭是可能的:一方不再发送,仍可继续接收。异常终止可使用 RST。主动关闭方可能保留一段 TIME_WAIT 状态,避免旧分节污染后续同五元组连接,并允许重发最后确认;这不是无意义的资源浪费。
TCP 具体提供了什么¶
- 序号与确认:标识字节位置并报告已接收范围。
- 校验和:检测损坏。
- 重传:超时或其他丢失信号触发再次发送。
- 接收缓存和流量控制:不让发送方淹没接收进程。
- 拥塞控制:根据网络反馈调节在途数据。
这些性质有代价:连接需要状态和握手,丢失时必须恢复有序字节,首部和算法更复杂。TCP 也不保证应用事务恰好执行一次,不保证固定时延,不提供消息机密性;TLS 和应用幂等仍有必要。
如何选择¶
| 需求 | 更自然的起点 | 仍需应用考虑 |
|---|---|---|
| 文件、网页、数据库连接 | TCP 或基于 QUIC 的可靠流 | 消息边界、超时、业务幂等、安全 |
| 少量独立查询 | UDP | 重试、放大攻击、响应匹配 |
| 实时语音视频 | UDP 或 QUIC 数据报 | 抖动缓冲、码率适应、丢包隐藏 |
| 多路复用且避免跨流阻塞 | QUIC | 用户态实现成本、UDP 可达性 |
选择不是“UDP 快、TCP 慢”这么简单。若应用在 UDP 上重新实现确认、拥塞控制和安全,最终复杂度可能超过直接使用成熟协议。真正的问题是应用需要哪种交付语义,以及能否承担实现和运维成本。
与 QUIC 的联系¶
QUIC 通常运行在 UDP 之上,把可靠流、拥塞控制、TLS 1.3 和连接迁移集成在用户态。多个 QUIC 流各自维护顺序,一条流丢包不会像 TCP 字节流那样阻塞其他流的数据交付。它仍受网络拥塞和物理传播限制,并不会让丢失的数据凭空出现。
自测
UDP 有校验和,为什么仍称不可靠?
校验和只帮助检测损坏,不负责重传、排序、去重和交付确认。能发现错误与能从错误中恢复是两件事。