onconnect一定先于onreceive触发,这是tcp三次握手完成、accept()成功获取$fd后,连接才被加入epoll监听可读事件的必然结果;onreceive仅在客户端send()导致内核缓冲区就绪、epoll返回epollin时触发。

onConnect一定先于onReceive触发,这是TCP状态机决定的
不是“大概率先”,而是底层保证的严格先后:只有三次握手完成、accept()成功拿到$fd后,连接才被加入 epoll 监听可读事件。没这个$fd,就根本不会进入数据接收流程。
常见错误现象是:在onConnect里立刻调用$server->send($fd, ...),但客户端收不到——其实不是顺序乱了,而是你发得太早,客户端还没来得及send()触发onReceive,或者网络延迟导致视觉上像“没收到”。
- 真正能触发
onReceive的,永远是客户端调用send()或write()之后,内核把数据放进 socket 接收缓冲区,epoll 返回EPOLLIN -
onConnect回调里没有$data参数,它只告诉你“人来了”,不带话 - 如果客户端在
connect()成功后**立刻**发数据(比如 HTTP Upgrade 请求),那onReceive会紧跟着onConnect触发,但仍是两个独立事件,且顺序不可逆
onReceive可能被合并或拆分,但绝不会早于onConnect
onReceive的触发次数 ≠ 客户端send()次数,这是 TCP 流式特性的必然结果,和事件顺序无关。
例如客户端连续两次send("hello"); send("world");,服务端可能一次收到"helloworld"(Nagle 算法/内核缓冲合并),也可能第一次onReceive只收到"hel",第二次才收到"loworld"(MTU 分片或 recv 缓冲区大小限制)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 这种拆包/粘包只影响
$data内容长度,不影响onConnect → onReceive这个链路的启动前提 - 如果你发现
onReceive比onConnect“先执行”,一定是日志打点位置错了——比如把echo "onReceive"写在了onConnect回调函数体外,或者用了异步日志没 flush - 调试时建议用
var_dump(getmypid(), $fd, 'onConnect')和var_dump(getmypid(), $fd, 'onReceive', strlen($data)),确认是否同一进程、同一$fd
dispatch_mode不为1时,onConnect/onReceive仍有序,但可能跨Worker
默认dispatch_mode = 2(固定模式),同一个$fd的所有事件都投递给同一个 Worker 进程,所以onConnect和后续onReceive必然在同个进程里顺序执行。
但如果改成dispatch_mode = 1(轮询)或3(IP哈希),onConnect和第一个onReceive仍由同一个 Reactor 线程发出、顺序入队;只是投递目标 Worker 可能不同——但 Swoole 内部管道保证指令按发出顺序消费,所以事件逻辑上依然有序。
- 真正要注意的是:不要在
onConnect里初始化仅限本 Worker 使用的资源(比如全局数组$clients[$fd] = [...]),因为后续onReceive可能被派到别的 Worker,查不到这个$fd - 若需跨 Worker 共享连接状态,必须用
Table、Redis或Atomic等进程安全结构 -
dispatch_mode = 5(一致性哈希)也遵守该顺序,但更强调连接亲和性,适合长连接场景
WebSocket里别混淆onConnect和onOpen
HTTP Server 没有onConnect,只有onRequest;WebSocket Server 则同时存在onConnect(TCP 层)和onOpen(协议层),二者不是一回事。
onConnect在 TCP 握手完成后立即触发,此时还只是裸连接;onOpen要等到 HTTP Upgrade 成功、WebSocket 协议握手完成(即Sec-WebSocket-Accept校验通过)才触发。中间可能失败(如 token 校验不通过),导致onConnect有而onOpen无。
- 业务逻辑该放哪?认证、鉴权、初始化用户 session 建议放在
onOpen里,因为它代表协议就绪;而连接统计、FD 记录可以放onConnect - 不要在
onConnect里调用$server->push(),此时 WebSocket 帧编码器可能未就绪,容易出错 - 浏览器端
ws.readyState === 0(CONNECTING)期间发的数据,服务端根本收不到;只有变成1(OPEN)后,onMessage才会被触发——这和onOpen的时机完全对应
onConnect里做 WebSocket 特定操作,或在onOpen里重复处理连接元信息。










