服务端接收二进制帧时$frame->opcode必须为0x02,发送需显式指定websocket_opcode_binary,客户端须设置binarytype='arraybuffer',分片需应用层拼接。

服务端接收二进制帧时,$frame->opcode 必须是 0x02
WebSocket 协议用 opcode 区分消息类型,0x02 才表示二进制帧。Swoole 服务端在 on('message') 回调中收到的 $frame 对象,其 $frame->opcode 值决定数据性质:
- 如果客户端发的是文本(如 JSON 字符串),
$frame->opcode是0x01,$frame->data是 UTF-8 字符串 - 如果客户端明确发二进制(如
Uint8Array或ArrayBuffer),$frame->opcode才是0x02,此时$frame->data是原始字节流(string类型,但内容为二进制) - 忽略
$frame->opcode直接处理$frame->data,可能把文本当二进制解析,或反之,导致乱码/解析失败
$server->push() 发送二进制数据必须显式指定 WEBSOCKET_OPCODE_BINARY
Swoole 默认用 WEBSOCKET_OPCODE_TEXT(即 0x01)发送,即使你传入的是二进制字符串(比如 file_get_contents('img.png')),客户端也会按文本帧接收,触发 onmessage 但 event.data 可能是损坏的字符串或直接报错。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 正确写法:
$server->push($fd, $binaryData, WEBSOCKET_OPCODE_BINARY) - 从 Swoole v4.4.12 起,第四个参数改为
$flags(如SWOOLE_WEBSOCKET_FLAG_FIN),但$opcode仍是第二个必需参数 - 不要依赖自动识别:Swoole 不会根据
$data内容类型推断opcode,必须手动设
客户端没设 binaryType,服务端发的二进制帧会被当成 Blob 或乱码
浏览器 WebSocket 对象默认把二进制消息当作 Blob 处理,event.data 是 Blob 实例,不是可直接解析的 ArrayBuffer。不设 binaryType 就读不到原始字节。
- 必须在
onopen后、首次onmessage前设置:ws.binaryType = 'arraybuffer' - 若设成
'blob',后续需调event.data.arrayBuffer()(返回 Promise),增加异步负担 - 服务端发的是
0x02帧,但客户端binaryType是'blob',event.data就是Blob;设成'arraybuffer'才是ArrayBuffer,可直接用DataView解析
大文件分片传输时,$frame->data 是独立帧,不是连续流
WebSocket 协议本身支持分片(continuation frame),但 Swoole 的 on('message') 回调**每次只触发一次 per 完整帧**,不会合并分片。也就是说,即使客户端用 slice() 分多次 send(),服务端收到的每个 $frame 都是独立的、完整的二进制帧,$frame->data 就是那一片的内容。
- 需要应用层拼接:服务端要自己维护缓冲区(如按
$frame->fd索引的Map),累计所有分片,直到满足长度条件再组装完整文件 - 不能假设
$frame->data是“一部分”,它永远是协议层认定的“一帧完整数据” - 注意内存:单帧最大 2MB(Swoole 默认限制),超大会被截断或连接关闭,分片是必须的
opcode 判断就直接 unpack() 或 json_decode(),或者客户端忘了设 binaryType 就去 new Uint8Array(event.data) —— 这两种情况都会静默失败,且错误现象不一致,调试时得先确认两端的帧类型和数据形态是否对齐。










