前五篇,我们一直在追一份数据包:它离开电脑,经过路由器,一跳一跳走向服务器。
假设它终于到了。服务器上可能同时运行着网站、数据库和其他服务;网站还可能正在接待成千上万名访客。服务器怎么知道,这份数据该交给哪个程序、哪个访客的连接?
答案要从端口说起。弄懂端口,再看 TCP 和 UDP,就能明白它们为什么都属于“传输层”,却提供了不同的服务。
IP 地址只能找到机器
把服务器的 IP 地址想成一栋楼的地址,大体上是有用的:数据可以靠它找到目标机器。但数据到了楼下,还得知道交给谁。
端口就是操作系统分配和识别网络通信的一种编号。比如,一个网站服务可能在 TCP 的443端口等待连接。
假设你的电脑向网站发起一次连接:
你的电脑 192.168.1.20:53142 ↓ 网站服务器 203.0.113.10:443冒号前是 IP 地址,冒号后是端口号。这里:
203.0.113.10指向目标服务器;443指向服务器上等待这类连接的服务;53142是电脑为这次通信使用的本地端口,便于接收返回的数据。
服务器回复时,方向反过来:
网站服务器 203.0.113.10:443 ↓ 你的电脑 192.168.1.20:53142如果你记得前一篇的 NAT:数据经过家用路由器时,来源 IP 和来源端口可能被改写。上图画的是电脑这一侧看到的通信信息,不代表互联网上每一跳看到的来源地址都完全一样。
端口也不是机器上真实存在的插孔。它是网络协议中的编号,由操作系统用来把收到的数据交给相应的网络程序。
同一个443,怎么接待许多访客?
服务器上的网站可以一直在443端口等待连接,并不需要为每个访客换一个服务端口。
来看两位访客:
访客 A 192.168.1.20:53142 → 服务器 203.0.113.10:443 访客 B 192.168.1.21:53142 → 服务器 203.0.113.10:443两台设备甚至碰巧用了相同的本地端口。服务器仍然能区分,因为来源 IP 不同。即使同一台电脑打开多个连接,也可以使用不同的本地端口。
对于 TCP 连接,常用下面四项描述通信双方:
来源 IP + 来源端口 + 目标 IP + 目标端口再加上使用的是 TCP 还是 UDP,就能区分不同协议中的通信。这比单说“连接了 443 端口”准确得多:端口必须放在 IP 地址和传输协议的上下文里看。
你可以把“服务器监听443”理解为它开着一个接待入口;进入后的每条通信,操作系统仍然能分清是谁和谁在说话。
为什么还需要 TCP 或 UDP?
IP 负责寻址和转发,但它并不承诺每个数据包都能到达,也不承诺先发的包一定先到。
应用程序对传输的要求却不一样。传一份文件时,你希望内容完整、顺序正确;进行实时通话时,迟到几秒的旧声音可能已经没有用,应用更关心及时处理当前声音。
TCP 和 UDP 给应用提供了两种不同的基础。它们都使用端口,但处理数据的方式不同。
UDP:按一份一份的消息发送
UDP 提供的是数据报服务。应用交给它一份消息,它把这份消息作为一个数据报发送。接收方如果收到了,也能按一份数据报来处理。
UDP 本身不先建立 TCP 那样的连接,也不负责替应用保证送达、按序到达或丢失后重传。它做得少,给上层留下了更多选择。
这并不等于“使用 UDP 的应用不可靠”。应用可以自己决定怎样确认、重传或纠错。QUIC 就建立在 UDP 之上,另外实现了连接管理、可靠传输等能力,HTTP/3 使用的正是 QUIC。
所以,更准确的说法是:
UDP自身不提供可靠、有序的传输;使用 UDP 的上层协议可以按需要补上这些能力。
DNS 查询常使用 UDP,但 DNS 也可以使用 TCP。实时音视频也常采用基于 UDP 的方案。不能看见“UDP”两个字,就断定它一定是游戏或语音,更不能断定它“一定比 TCP 快”。实际速度还取决于应用要实现什么、网络状况如何,以及丢包后怎么处理。
TCP:建立连接,交付有序的字节流
TCP 提供的是另一种服务:可靠、有序的字节流。
通信双方先建立连接。传输过程中,TCP 会处理编号、确认、重传等问题,努力把发送方交出的字节按顺序交给接收方。下一篇会专门拆开讲建立和关闭连接,第八篇再讲它怎样处理丢包与拥塞。
这里有个很容易被忽略的词:字节流。
假设程序连续写入两次:
第一次写入:“你好” 第二次写入:“世界”接收方不能想当然地认为,自己一定会收到两份恰好对应的“消息”。它可能一次读到“你好世界”,也可能分几次读到。TCP 保证的是字节顺序,不替应用规定“第一条消息在哪里结束,第二条在哪里开始”。
如果应用需要区分一条条消息,就得自己设计边界,例如先写明消息长度,或者约定分隔方式。HTTP 等应用层协议要处理的,正包含这类“这些字节是什么意思”的问题。
TCP 的“可靠”也有边界。它能确认数据在连接中被另一端的 TCP 接收,不等于网站已经把订单写入数据库,更不等于用户重复点击付款时业务只会执行一次。传输成功和业务成功,不是一回事。
到底该用哪个?
把两者放在一起看,区别就清楚了:
| 问题 | TCP | UDP |
|---|---|---|
| 发送前是否建立传输连接? | 是 | 否 |
| 是否由协议自身处理有序、可靠传输? | 是 | 否 |
| 交给应用的是什么? | 连续的字节流 | 一份份数据报 |
| 丢包后的处理 | TCP 有确认和重传机制 | 由使用它的上层协议决定 |
选用哪个,不是按“TCP 稳、UDP 快”二选一。要看应用究竟需要什么,以及它愿意自己承担多少传输工作。
访问网页就是一个好例子。很多 HTTPS 连接运行在 TCP 之上;HTTP/3 则使用建立在 UDP 之上的 QUIC。用户看到的都是网页,但底层传输方案可以不同。443也不能脱离 TCP 或 UDP 单独理解:TCP443和 UDP443是不同协议中的端口。
在电脑上看见真实连接
Windows 用户可以打开几个网页,再在命令提示符中输入:
netstat -ano -p tcp在输出中找状态为ESTABLISHED的行。你可能看到类似内容:
协议 本地地址 外部地址 状态 PID TCP 192.168.1.20:53142 203.0.113.10:443 ESTABLISHED 1234这是示意,不是你电脑应当出现的固定地址。试着辨认本地 IP、本地端口、远端 IP、远端端口。最后一列 PID 是进程编号。
再运行:
netstat -ano -p udp你会发现 UDP 的显示方式与 TCP 连接列表不同:UDP 没有ESTABLISHED这种 TCP 连接状态。
如果你刚打开了网页,却没找到对应的 TCP443,先别急着判断命令失效。浏览器可能使用了 HTTP/3,也可能复用了已有连接;连接还可能很快结束。这个练习的重点,是读懂一行连接信息,而不是保证抓到某个指定网站。
今天把从“机器”到“程序”的最后一步补上了:IP 帮数据找到目标设备,端口帮助设备区分通信;TCP 和 UDP 决定应用拿到怎样的传输服务。
下一篇,我们顺着最常见的 TCP 连接继续问:既然要先建立连接,为什么大家总说“三次握手”?关闭连接时又发生了什么?
参考资料:TCP 规范 RFC 9293、UDP 规范 RFC 768、QUIC 规范 RFC 9000、微软netstat使用说明。