# MQTT、TCP、WebSocket 关系总结
从 MQTT over TCP / WebSocket 到浏览器为什么需要 WebSocket
1. 问题起点:为什么 MQTT Broker 同时支持 TCP 和 WebSocket?
观察 MQTT Broker 时,经常会看到多个监听端口:
1883 MQTT TCP
8883 MQTT TLS
8083 MQTT WebSocket
8084 MQTT WebSocket TLS
问题:
MQTT 本来就是基于 TCP 的协议,为什么还需要 WebSocket?
是不是 MQTT 本身和 WebSocket 有关系?
2. MQTT over xxx 到底是什么意思?
首先理解:
MQTT over xxx 表示 MQTT 协议运行在什么传输方式之上。
MQTT 本身负责:
- 消息格式
- Topic
- Publish
- Subscribe
- QoS
- Broker消息分发逻辑
而 over 后面的协议负责:
- 如何承载 MQTT 数据
- 如何传输 MQTT 数据
所以:
MQTT over TCP
表示:
MQTT协议通过TCP传输
MQTT over WebSocket
表示:
MQTT协议通过WebSocket传输
3. MQTT over TCP
这是 MQTT 最原始、最常见的方式。
协议栈:
MQTT Packet
|
TCP
|
IP
TCP里面的数据:
TCP Payload
+----------------+
| MQTT Packet |
+----------------+
例如客户端发送:
CONNECT
实际上 TCP 中:
MQTT Fixed Header
+
Variable Header
+
Payload
服务器:
TCP recv()
↓
MQTT Parser
↓
CONNECT
PUBLISH
SUBSCRIBE
这里完全没有 WebSocket。
4. MQTT over WebSocket
后来为了支持某些场景,增加:
MQTT over WebSocket
协议栈:
MQTT Packet
↓
WebSocket Frame
↓
TCP
↓
IP
数据实际上是嵌套的:
TCP Payload
+--------------------------------+
| WebSocket Frame |
| |
| +----------------------+ |
| | MQTT Packet | |
| +----------------------+ |
| |
+--------------------------------+
发送过程:
客户端:
生成 MQTT PUBLISH
↓
放入 WebSocket Frame
↓
通过 TCP 发送
服务器:
TCP recv()
↓
WebSocket解析
↓
取出MQTT Packet
↓
MQTT解析
↓
执行PUBLISH
5. 为什么服务器必须支持 WebSocket?
因为两种连接的数据格式不同。
MQTT/TCP
客户端:
MQTT
|
TCP
服务器:
TCP接收
↓
MQTT解析
MQTT/WebSocket
客户端:
MQTT
|
WebSocket
|
TCP
服务器:
TCP接收
↓
WebSocket解析
↓
MQTT解析
如果服务器只有:
TCP
|
MQTT Parser
那么收到:
WebSocket Header
+
MQTT Packet
会失败。
因为 MQTT Parser 期待:
MQTT Fixed Header
而不是:
WebSocket Header
6. MQTT为什么需要WebSocket?
继续追问:
为什么设备不用 WebSocket?
为什么 MQTT 还要增加这一层?
原因:
不是 MQTT 不能用 TCP。
而是:
不同客户端环境能力不同。
7. 普通 MQTT 客户端可以直接使用 TCP
例如:
- ESP32
- Linux C程序
- Android原生程序
- Java程序
- Python程序
都可以:
socket()
connect()
send()
recv()
所以:
MQTT Client
|
TCP Socket
|
Broker
即可。
例如:
ESP32
MQTT Client
|
TCP 1883
|
MQTT Broker
这是 IoT 最常见方式。
8. 真正需要 WebSocket 的主要是浏览器
问题:
浏览器里的 JavaScript:
不能直接:
socket(AF_INET)
也不能:
connect()
send()
recv()
直接操作 TCP Socket。
原因:
浏览器安全模型限制。
如果网页可以任意 TCP:
例如:
网页
|
TCP
|
192.168.1.100:22
可能导致:
- 扫描用户内网
- 访问内部服务
- 发起非法连接
所以浏览器隐藏了原始 Socket 能力。
9. 浏览器如何获得类似 TCP 长连接能力?
浏览器虽然不能直接 TCP Socket,
但是很多应用需要:
- 长连接
- 双向通信
- 服务端主动推送
于是浏览器提供:
WebSocket
结构:
浏览器
|
WebSocket
|
TCP
|
服务器
WebSocket 可以理解为:
浏览器提供的、类似 TCP 长连接体验的标准通信入口。
10. 所以 MQTT 有两类客户端
设备客户端
例如:
ESP32:
MQTT
|
TCP
|
Broker
特点:
- 协议简单
- 开销小
- 适合 MCU
浏览器客户端
例如:
网页控制台:
MQTT
|
WebSocket
|
TCP
|
Broker
原因:
浏览器不能直接 TCP Socket。
11. 为什么不全部使用 WebSocket?
因为设备没有必要。
例如 ESP32:
直接:
MQTT
|
TCP
已经足够。
如果改成:
MQTT
|
WebSocket
|
TCP
增加:
- WebSocket解析
- 更多包头
- 更多状态维护
- 更多内存消耗
对于:
- MCU
- 传感器
- 低功耗设备
没有意义。
12. 这个规律扩展到其他协议
MQTT只是一个例子。
很多协议原本:
应用协议
|
TCP
如果需要进入浏览器:
变成:
应用协议
|
WebSocket
|
TCP
IM聊天
普通客户端:
IM协议
|
TCP
网页:
IM协议
|
WebSocket
|
TCP
游戏消息
简单实时游戏:
游戏协议
|
WebSocket
|
TCP
STOMP
STOMP
|
WebSocket
|
TCP
JSON-RPC
JSON-RPC
|
WebSocket
|
TCP
13. 为什么 WebSocket 这么常见?
因为它刚好补充浏览器缺少的能力。
TCP:
负责:
可靠字节传输
WebSocket:
增加:
消息边界
双向通信
浏览器支持
应用协议:
增加:
业务语义
例如:
MQTT:
消息模型
Topic
发布订阅
QoS
14. 但是不是所有实时通信都 WebSocket?
不是。
WebRTC
用于:
- 视频通话
- 音频
- P2P
协议:
WebRTC
|
ICE
DTLS
SRTP
|
UDP
原因:
需要:
- 低延迟
- 可以丢包
- 实时性
SSE
用于:
服务器单向推送:
Server ---> Browser
例如:
- 新闻
- 日志
- 股票
15. 最终理解
整个关系:
MQTT
|
+----------+----------+
| |
MQTT/TCP MQTT/WebSocket
| |
TCP WebSocket
|
TCP
三者职责:
TCP:
负责可靠传输字节
WebSocket:
解决浏览器无法直接使用TCP Socket的问题,
提供双向消息通道
MQTT:
定义设备之间消息格式和流转模型
最终一句话:
MQTT 原本就是运行在 TCP 上的物联网消息协议。WebSocket 是后来为了让浏览器能够使用 MQTT 而增加的一种传输承载方式。由于浏览器不能直接创建 TCP Socket,所以很多原本基于 TCP 长连接的应用协议,在需要支持浏览器时,会选择运行在 WebSocket 之上。
这就是:
- MQTT over WebSocket
- STOMP over WebSocket
- JSON-RPC over WebSocket
- IM WebSocket
- 游戏 WebSocket
出现的根本原因。
浙公网安备 33010602011771号