你机器上几乎每个网络应用都会直接使用 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 之上添加的任何可靠性机制。

关键区别

下表总结了对比:

属性TCPUDP
连接面向连接,先握手无连接,无设置
数据模型连续字节流独立数据报
可靠性检测丢失并重传无交付或重传机制
排序按顺序交付字节数据报可能乱序到达
流量和拥塞控制内建于 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 查看实时套接字状态。关于检查监听端口的指南涵盖了更多过滤器和工具。