onmessage仅在swoole\websocket\server中有效,处理已解析的websocket帧;onreceive用于tcp/udp原始字节流,需自行处理粘包等;onpacket专用于udp,语义更清晰。

Message回调用于WebSocket连接,Data回调是底层TCP/UDP收包的原始数据入口,二者不在同一抽象层级,不能混用或互相替代。
onMessage 只在 WebSocket Server 中有效
当你使用 Swoole\WebSocket\Server 时,onMessage 是唯一推荐的客户端消息入口。它只接收已解析完成的 WebSocket 帧(TEXT 或 BINARY),自动处理握手、掩码解码、分片重组等。如果你在 TCP 或 HTTP Server 上注册 onMessage,它根本不会被触发。
- 错误现象:
onMessage回调函数从未执行,但onReceive却频繁触发 → 很可能你用的是Swoole\Server或Swoole\Http\Server,而非 WebSocket 类型 - WebSocket 连接建立后,所有后续帧都走
onMessage,包括心跳 ping/pong(若未单独设onPing/onPong) - 参数
$frame是Swoole\WebSocket\Frame对象,含data、opcode、finish等字段,不是裸字节流
onReceive 是 TCP/UDP 的原始数据回调
onReceive 出现在 Swoole\Server(TCP)和 Swoole\UDP\Server 中,它收到的是未经协议解析的原始字节流。对 TCP 来说,它不保证一次回调对应一个“完整业务包”,可能粘包、半包;对 UDP,则每次回调对应一个完整 UDP 包(最大 64KB)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 常见误用:在 WebSocket Server 中监听
onReceive→ 实际不会触发,因为 WebSocket Server 已接管并封装为onMessage - 若需自定义 TCP 协议(如私有二进制协议),必须用
onReceive+set配置open_length_check或package_max_length等参数做包解析 - UDP 场景下,
onReceive的$from_id是reactor_id,没有$fd概念(无连接),所以不能调用send(),得用sendto()
onPacket 专用于 UDP 数据包解析
当使用 Swoole\Server 启动 UDP 类型监听(SWOOLE_SOCK_UDP)时,onPacket 是更合适的回调——它比 onReceive 多一层语义:明确表示“这是一个完整的 UDP 数据报”。虽然功能上与 onReceive 在 UDP 下行为一致,但语义清晰、可读性高,且 Swoole 内部做了轻量适配。
- 若未设置
onPacket,UDP 收包默认仍会进入onReceive(兼容旧写法) - 不要在 TCP Server 中注册
onPacket→ 不会触发,也无意义 - 参数签名不同:
onPacket的回调函数接收($server, $data, $client_info),其中$client_info包含address和port,而onReceive的 UDP 模式下$fd为 -1,$from_id为 reactor ID
容易忽略的底层细节
真正影响回调行为的不是函数名,而是 Server 实例类型和 listen() 时指定的 $socket_type。Swoole 不会校验你在 HTTP Server 上注册了 onMessage 是否合理,它只是静默忽略。
- 检查当前 Server 类型:
var_dump(get_class($server))—— 必须是Swoole\WebSocket\Server才能用onMessage - UDP 场景下,
sendto()的$server_socket参数若为空,会使用第一个 UDP 监听端口;若有多个,必须显式传入对应 socket 名称 -
onMessage抛出异常会导致连接被强制关闭,而onReceive异常仅中断当前包处理,连接保持活跃










