你机器上几乎每个网络应用都会直接使用 TCP 或 UDP,或者通过建立在其中之一的协议来使用它们。TCP 会跟踪连接并传递有序的字节流,代价是额外的往返和数据维护。UDP 发送独立的数据报,不进行传输层恢复,使应用能更好地控制时序和重传。这一区别有助于解释为什么文件传输会恢复丢失的数据,而实时通话可能会跳过迟到的数据包并继续。
本指南解释 TCP 和 UDP 有何不同、哪些服务依赖它们,以及如何在 Linux 系统上判断某个端口使用的是哪种协议。
两种传输协议
TCP 和 UDP 位于传输层,比 IP 高一层。IP 在主机之间移动数据包,但不保证它们能到达、只到达一次或按顺序到达。传输协议负责决定如何处理这些问题。
TCP(Transmission Control Protocol,传输控制协议)提供可靠、有序的字节流。UDP(User Datagram Protocol,用户数据报协议)发送独立的数据报,传输层处理最少。如果应用需要基于 UDP 获得可靠性,它必须自己提供这种行为,或者使用另一种建立在 UDP 之上的协议。
TCP 如何工作
TCP 是面向连接的。在应用数据通常开始流动之前,双方通过三次握手建立连接:客户端发送 SYN,服务器回复 SYN-ACK,客户端再用 ACK 应答。此设置会同步序列号,并让两个端点都能跟踪连接。
连接建立后,TCP 提供若干重要行为:
- 可靠交付。 TCP 检测丢失或损坏的段,并在连接仍然可用时重传数据。如果恢复失败,应用会收到连接错误,而不是成功交付确认。
- 有序交付。 段携带序列号,因此即使网络按乱序交付,接收方也会按发送顺序重新组装它们。
- 流量控制和拥塞控制。 TCP 会调整发送速率,以避免压垮接收方或网络。
- 连续的字节流。 应用按顺序读取字节,但 TCP 不保留各个写入之间的边界。应用必须定义自己的消息格式。
这些机制有代价:握手会在数据传输前增加往返,确认和重传会增加开销和延迟。对于文件下载或 SSH 会话,这个代价是值得的,因为丢失数据会破坏结果。
UDP 如何工作
UDP 是无连接的。没有握手;发送方只是把数据放入数据报并发送。接收方可能收到,可能乱序收到,也可能完全收不到,而 UDP 本身不会纠正其中任何情况。
与 TCP 的字节流不同,UDP 保留数据报边界。应用发送的一个数据报如果到达,就会作为一个数据报交付。UDP 首部还有一个校验和字段,用于检测损坏,但 UDP 不确认数据包,也不重传丢失的数据。
UDP 有几个实际特点:
- 无需连接建立。 应用无需完成传输握手就可以发送第一个数据报。
- 协议开销低。 UDP 首部为 8 字节,而 TCP 首部至少为 20 字节。
- 没有传输层排序。 延迟或丢失的数据报不会让 UDP 在交付另一个数据报之前等待它。
- 由应用控制恢复。 应用决定是忽略丢失、重试请求,还是添加确认和重传。
UDP 并非在每个应用中都自动更快。更小的首部和无需连接建立可以降低延迟,但实际性能取决于应用协议、网络条件、数据包大小,以及 UDP 之上添加的任何可靠性机制。
关键区别
下表总结了对比:
| 属性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接,先握手 | 无连接,无设置 |
| 数据模型 | 连续字节流 | 独立数据报 |
| 可靠性 | 检测丢失并重传 | 无交付或重传机制 |
| 排序 | 按顺序交付字节 | 数据报可能乱序到达 |
| 流量和拥塞控制 | 内建于 TCP | 必须由应用协议处理 |
| 首部大小 | 20 字节或更多 | 8 字节 |
| 典型用途 | 基于 HTTP/1.1 或 HTTP/2 的 Web、电子邮件、SSH、文件传输 | DNS 查询、DHCP、NTP、语音、游戏和 QUIC |
服务使用哪种协议
服务使用哪种协议取决于它需要有序字节流、独立消息、低建立延迟,还是应用特定的恢复控制。
常见 TCP 用途
- HTTP/1.1 和 HTTP/2 使用 TCP,而 HTTP/3 使用基于 UDP 的 QUIC。
- SSH 用于远程登录。
- SMTP、IMAP 和 POP3 用于电子邮件。
- FTP 用于文件传输。
常见 UDP 用途
- DHCP 用于在启动时分配地址,那时甚至还无法建立连接。
- NTP 用于时间同步。
- 语音、视频会议和许多在线游戏 在迟到数据不如当前数据有用时,通常使用 UDP。
一些应用协议可以同时使用两种传输。DNS 通常通过 UDP 发送查询,但 DNS 实现也必须支持 TCP。TCP 用于区域传送等操作,以及响应通过 UDP 被截断时。EDNS 允许 DNS 端点声明支持更大的 UDP 消息,这减少但不能消除 TCP 回退。
QUIC 是另一个重要案例。它运行在 UDP 之上,但自行实现可靠流、拥塞控制、加密和连接管理。HTTP/3 使用 QUIC,因此现代 Web 流量并不局限于 TCP。
端口号是为 TCP 和 UDP 分别分配的。因此,一个服务可以在两种传输上使用相同的数字端口,正如 DNS 在端口 53 上所做的那样。
查看端口使用哪种协议
在 Linux 上,使用 ss 命令同时列出 TCP 和 UDP 套接字:
终端sudo ss -tulpn这些标志选择 TCP(-t)和 UDP(-u)套接字、监听套接字(-l)、进程信息(-p),以及数字地址和端口(-n)。输出每行列出 一个套接字:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=712,fd=12))
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:* users:(("dhclient",pid=920,fd=6))
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=712,fd=13))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1043,fd=3))
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1410,fd=6))Netid 列标明了传输协议。TCP 监听器以 LISTEN 状态出现,而未连接的 UDP 套接字通常显示为 UNCONN。注意,本地解析器在 udp 和 tcp 上都占用了端口 53,这与前面描述的 DNS 行为相匹配:查询通常通过 UDP 传输,但该服务仍然在 TCP 上监听,以处理更大的响应和区域传送。DHCP 客户端位于 UDP 端口 68,而 SSH(端口 22)和 Web 服务器(端口 80)使用 TCP。
要查看 DNS 的已注册传输映射,请搜索 /etc/services:
grep -E '^[[:space:]]*domain[[:space:]]' /etc/services该文件显示的是约定俗成的服务注册,而不是当前正在运行的进程。使用 ss 查看实时套接字状态。关于检查监听端口的指南涵盖了更多过滤器和工具。