workerman 中 websocket 与 tcp 服务本质不同:websocket 需 http 升级握手、自动解帧、提供 onopen/onclose 等语义化事件;tcp 直连无握手、收原始字节流、需自处理粘包与心跳。

Workerman 中的 WebSocket 和 TCP 服务不是“两种写法的区别”,而是协议语义、事件模型和数据处理逻辑的根本不同——用错一个,连接能建起来,但消息收不到或解析失败。
WebSocket 服务必须走 HTTP 升级握手,TCP 服务直接监听端口
Workerman 的 WebSocket 服务底层仍基于 TCP,但框架强制要求你使用 WebWorker 或 Worker 配合 WebServer(或直接 new Worker("websocket://0.0.0.0:2000")),它会自动拦截并处理 RFC6455 握手请求:
- 客户端
new WebSocket("ws://127.0.0.1:2000")发起的是带Upgrade: websocket头的 HTTP 请求 - Workerman 内置的 WebSocket 解析器会校验
Sec-WebSocket-Key,生成Sec-WebSocket-Accept并返回101 Switching Protocols - 握手失败时,浏览器控制台报
WebSocket connection to 'ws://' failed,且不会触发onConnect
而 TCP 服务(如 new Worker("tcp://0.0.0.0:8080"))跳过所有 HTTP 层,onConnect 在 connect() 成功后立刻触发,不等任何头信息——这也意味着你不能直接用浏览器 new WebSocket() 连这个端口。
onMessage 回调接收的数据单位完全不同
WebSocket 的 onMessage 收到的是完整、解帧后的消息体(字符串或 Binary);TCP 的 onMessage 收到的是原始字节流,可能粘包、可能截断:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- WebSocket:发送
ws.send("hello")→ 服务端onMessage($connection, $data)中$data === "hello"(类型为 string) - TCP:客户端连续 send("a")、send("b") → 服务端一次
onMessage可能收到"ab";或 send("hello world") 被拆成两次触发,第一次$data = "hello ",第二次$data = "world" - 所以 TCP 服务必须自己实现分包逻辑(比如加长度头、换行符分隔),WebSocket 服务不用管帧格式
连接状态事件不可互换
WebSocket 服务提供标准的 onOpen / onClose / onError 事件,对应 RFC6455 的连接生命周期;TCP 服务只有 onConnect / onMessage / onClose,且 onClose 触发时机更底层(比如 recv() 返回空):
- WebSocket 的
onClose($connection, $code, $reason)会携带标准关闭码(如1000正常关闭、1006异常断连),可用于区分主动断开和网络中断 - TCP 的
onClose不带任何语义,只表示 socket fd 关闭;如果客户端静默掉线(如断网),可能要靠心跳超时才能感知 - Workerman 的
WebSocket服务默认启用 ping/pong 心跳,TCP服务需手动在onMessage或定时器里实现
协议混用时容易踩的坑
最常见错误是把 WebSocket 服务当成裸 TCP 用,或反过来用 TCP 客户端连 WebSocket 端口:
- 用
telnet 127.0.0.1 2000连 WebSocket 端口 → 服务端收不到onConnect,因为没发 HTTP 握手请求,连接会被直接拒绝或挂起 - 在 WebSocket 服务里对
$connection->send()传入未 UTF-8 编码的二进制数据 → 浏览器抛SyntaxError: The received data is not valid UTF-8(除非显式用ArrayBuffer) - 给 TCP 服务配了
ssl://但没配证书路径 → 启动报PHP Warning: stream_socket_server(): unable to connect to ssl://...,而 WebSocket 的wss://必须配context且证书有效
真正关键的不是“能不能跑起来”,而是消息边界是否可控、断连是否可检测、错误是否可归因——这些在 WebSocket 层已被封装,在 TCP 层全得你自己填。









