onMessage不触发,先确认连接是否真正建立成功;检查netstat监听状态、TCP三次握手是否完成、心跳是否被硬件忽略;注意硬件发的是裸字节流,需自定义协议分包,避免阻塞操作导致数据积压。

onMessage不触发,先看连接是否真建立成功
Workerman的onMessage只在连接已就绪、且有完整数据到达时才触发。如果硬件设备(比如PLC、传感器)发了数据但onMessage完全没反应,大概率不是解析问题,而是连接根本没建稳。
常见错误现象:客户端日志显示“已连接”,但onConnect没执行;或者onConnect执行了,onMessage始终沉默。
- 用
netstat -anp | grep :端口号确认服务端监听正常,且硬件IP确实在ESTABLISHED状态 - 检查硬件设备是否真的完成了TCP三次握手——有些嵌入式设备发完SYN就卡住,或仅单向发包不收ACK
- Workerman默认启用心跳检测,若硬件不响应ping帧(如
ping_interval超时),连接会被主动断开,onClose会触发,但你可能没监听它
硬件发的是裸字节流,不是HTTP,别期待自动分包
PLC、串口转网关、工控模块等设备几乎都走原始TCP,不带HTTP头、不分chunk、不设Content-Length。Workerman收到的就是一坨连续字节,onMessage回调里的$data就是原始二进制或乱码字符串——这不是bug,是协议本该如此。
常见错误现象:echo $data看到一堆不可见字符、长度忽长忽短、偶尔截断、甚至空字符串。
- 必须自己定义应用层协议:比如以
\n、\r\n或固定长度(如16字节/帧)为边界 - 不要依赖
$_POST或$request->post()——这些只对HTTP有效,TCP下压根不存在 - 开启
$connection->protocol = 'text'或自定义协议类,让Workerman帮你按行或按帧拆包(否则所有数据会攒在缓冲区,直到超时或缓冲满才吐一次)
发送太快,接收被系统缓冲区“吞掉”了
硬件设备常以毫秒级间隔连续发多条指令(比如每10ms读一次寄存器),而Workerman的事件循环若被阻塞(如定时器里密集send()、或onMessage里做了耗时同步操作),会导致onMessage回调迟迟得不到调度,数据全堆在内核recv缓冲区里不动。
典型表现:Wireshark能看到设备确实在发包,但PHP里onMessage几秒后才突然一次性收到十几条拼在一起的数据。
- 避免在
onMessage里做sleep、file_get_contents、curl等阻塞操作 - 如果必须轮询硬件,改用
Worker::signal或Timer::add异步调度,别卡主线程 - 紧急补救:在
onMessage处理完后手动调用$connection->baseRead($connection->getSocket()),强制触发下一轮读取(参考PLC通信真实案例)
编码/字节序/校验字段导致数据被静默丢弃
很多工业协议要求首字节为命令码、末尾含CRC16校验、或整数字段用大端序(Big-Endian)。Workerman不会帮你校验或转换——它只负责把收到的字节原样交给onMessage。如果你的解析逻辑一上来就unpack('V', $data)却忘了设备发的是N(大端ulong),结果就是解出0或负数,后续直接跳过处理。
常见错误现象:onMessage能触发,但你的业务逻辑总判断“非法帧”然后return,看起来像没收到。
- 先用
bin2hex($data)打印原始十六进制,对照设备手册确认帧结构是否匹配 - 检查是否漏了粘包处理:两条帧连在一起发过来,你按单帧解析就会失败
- 确认
$connection->transport是tcp而非ssl——某些硬件不支持TLS握手,强行配SSL会导致连接后立即断开,onMessage自然不会触发
onMessage函数,而是确认那几字节数据从硬件引脚出发,经过网线、交换机、Linux协议栈、Workerman事件循环,最后稳稳落在$data变量里——中间任何一环掉链子,它都不会提醒你。

















