网络知识

TCP 长连接与 WebSocket 连接有什么区别

从协议分层的角度说明 TCP 长连接与 WebSocket 的关系与差异,包括握手方式、消息边界、经过中间设备时的表现,以及它们在实际使用中各自会遇到什么问题。

本文解决的问题:看到客户端里有不同的连接方式,想知道 TCP 长连接和 WebSocket 到底差在哪。

先纠正一个常见的误解:TCP 长连接和 WebSocket 不是并列关系。WebSocket 是建立在 TCP 之上的应用层协议,任何一个 WebSocket 连接底下都必然有一条 TCP 连接。因此「哪个更快」这个问题本身是不成立的——它们不在同一层。

真正有意义的比较是:直接使用 TCP 长连接,和在 TCP 之上再套一层 WebSocket,两者的差别在哪里

分层关系

从下往上看,一次 WebSocket 通信的分层是这样的:

应用数据

WebSocket 帧(消息边界 + 控制帧)

TLS 加密(如果是 wss://)

TCP(可靠传输、顺序保证、重传)

IP(路由寻址)

直接使用 TCP 长连接时,中间的 WebSocket 那一层不存在,应用数据直接交给 TCP。

差别一:如何建立连接

TCP 长连接的建立就是标准的三次握手:客户端发 SYN,服务端回 SYN-ACK,客户端再回 ACK。握手完成后,双方可以随时互相发送字节流。整个过程与 HTTP 无关,中间设备看到的就是一条普通的 TCP 连接。

WebSocket 则多了一个步骤。它先发起一个看起来完全像 HTTP 的请求

GET /path HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <随机字符串>
Sec-WebSocket-Version: 13

服务端如果同意,返回 101 Switching Protocols。从这一刻起,这条连接不再按 HTTP 的规则工作,而是切换成 WebSocket 的帧格式。

这个设计有一个实际后果:WebSocket 的开场白与普通网页请求几乎一样。对只做浅层检查的中间设备来说,它和一次普通的 HTTPS 访问难以区分。这也是为什么在某些限制较严格的网络里,基于 WebSocket 的连接更容易建立成功。

差别二:有没有消息边界

这是两者最实质的技术差异。

TCP 是字节流协议,没有消息边界的概念。 如果你连续发送三条消息,接收端可能一次性收到全部内容,也可能分四次收到,甚至可能把第一条的后半部分和第二条的前半部分放在同一次读取里。这就是常说的「粘包」与「拆包」。

因此直接用 TCP 时,应用层必须自己解决分包问题,常见做法是在每条消息前加上长度字段,或者用特定分隔符。

WebSocket 在 TCP 之上定义了帧结构,每一帧带有长度信息和类型标识。接收端收到的一定是完整的一条消息,不需要自己处理边界。

代价是每帧多出 2 到 14 字节的头部开销。对绝大多数使用场景来说,这个开销可以忽略。

差别三:内建的控制机制

WebSocket 协议定义了几种控制帧:

  • Ping / Pong:用于探测连接是否仍然存活;
  • Close:用于优雅地关闭连接,双方都能知道对方主动断开了。

直接使用 TCP 时,这些机制需要应用自己实现。TCP 本身有 keepalive 选项,但默认间隔通常是两小时,对于需要及时发现断线的场景来说毫无用处。

为什么连接会莫名断开

这是实际使用中最常遇到的问题,而且它与选用哪种协议关系不大

主要原因有三个:

中间设备的空闲超时

家用路由器、企业防火墙、运营商的 NAT 设备,都会维护一张连接状态表。表的容量有限,所以设备会给每条连接设置一个空闲超时——一段时间内没有数据往来,就把这条记录删掉。

超时时间因设备而异,家用路由器常见的是几分钟到几十分钟。记录被删除后,双方仍然认为连接存在,但实际上数据已经无法通过。表现就是「看起来连着,但发什么都没反应」。

解决办法是心跳:定期发送一个很小的数据包,让连接保持活跃。间隔需要小于中间设备的超时时间。这也是 WebSocket 定义 Ping/Pong 帧的原因。

移动网络的 IP 变化

手机在基站之间切换、或者从 Wi-Fi 切到移动数据时,IP 地址会改变。TCP 连接由「源 IP + 源端口 + 目标 IP + 目标端口」四元组唯一标识,IP 一变,原来的连接就自动失效了。

这种断开是必然的,任何协议都无法避免,只能靠客户端快速重连来减少感知。相关表现见手机更换网络后需要重新连接吗

链路质量导致的重传超时

丢包严重时,TCP 的重传会不断退避,连续多次失败后连接会被判定为断开。这属于链路质量问题,见什么是网络延迟、抖动和丢包

实际选择

对普通用户来说,这个选择通常不需要自己做——客户端会根据配置自动处理。

如果确实需要判断,可以参考这个粗略的经验:

情况倾向
网络环境宽松,追求最小开销直接 TCP
网络中间设备较多、限制较严WebSocket(走 443 端口时更不容易被拦)
需要频繁收发小消息WebSocket(省去自己处理边界)
连接经常断与协议无关,先调心跳间隔

需要强调最后一行:如果连接总是断,换协议通常解决不了问题。先按长连接容易中断的网络环境排查方法排查,找到真正的原因再说。

一个常见的误判

有人会观察到「换成 WebSocket 之后稳定了」,并据此认为 WebSocket 更稳定。实际上更可能的解释是:切换配置时客户端重建了连接,或者新配置的心跳间隔更短、端口更常见。

变量一次只改一个,才能得到有意义的结论。这一点在所有网络排查中都适用。

安全提示

  • 不要为了「优化连接」随意修改客户端的高级参数,改动前请记录原始值。
  • 抓包分析涉及网络流量内容,不要在公共设备上进行,也不要把抓包文件公开分享。

本文相关常见问题

WebSocket 一定比 TCP 快吗?

不存在这种比较。WebSocket 运行在 TCP 之上,它的传输性能就是底层 TCP 的性能,额外开销只有很小的帧头。

为什么有些网络下 WebSocket 更容易连上?

因为它的握手是标准的 HTTP 升级请求,走 443 端口时与普通 HTTPS 流量在中间设备看来非常相似,更不容易被简单的规则拦掉。

连接总是断开是协议的问题吗?

通常不是。更常见的原因是中间设备的空闲超时回收,或者移动网络切换导致的 IP 变化。心跳间隔设置得当可以缓解前者。

我需要自己选择用哪种吗?

一般不需要。客户端通常会根据配置自动使用,普通用户不必手动干预。

INVITE CODE

准备注册 FlyingBird 飞鸟?

AMM
复制并前往注册

打开注册页面后,如系统要求填写优惠码,请粘贴 AMM。价格、套餐与可用状态请以用户中心实时页面为准。