$connection->send()不生效最常见原因是连接已断开但未检测,需发送前调用$connection->isConnected()校验;TCP裸发无协议头,须自行保证数据格式、编码一致及序列化处理。

直接用 $connection->send(),但必须确保连接还活着、数据格式正确、编码无误——否则发出去等于没发。
为什么 $connection->send() 有时不生效
最常见原因是连接已断开但代码没感知,还在往一个已关闭的 $connection 对象发数据。Workerman 不会主动抛异常,send() 返回 false 或静默失败,尤其在 TCP 长连接中容易被忽略。
- 务必在
send()前检查$connection->isConnected()(Workerman 4+)或isset($connection->id)(旧版) - TCP 协议下没有自动重连,客户端断线后服务端不会自动清理连接对象,得靠
onClose回调手动清理映射 - 如果用了自定义协议(比如定长包、分隔符),
send()发出的原始字节若不符合协议解析规则,客户端收不到或解析错位
怎么安全地向指定 TCP 客户端发消息
核心是维护一个可用连接池,并在发送前校验状态。不要依赖全局数组硬查,要结合连接生命周期事件。
- 在
onConnect中给$connection绑定唯一标识,例如:$connection->uid = $some_id; - 用
$worker->connections(内置连接集合)或自定义数组(如$worker->uidConnections)做映射,但注意多进程下该数组仅本进程有效 - 发送前加判断:
if ($connection->isConnected()) { $connection->send($data); } - 若需跨进程推送,必须引入外部存储(如 Redis)或改用
GatewayWorker,单靠$worker->connections无法共享
TCP 下 send() 的数据格式要注意什么
Workerman 的 send() 是裸 TCP 发送,不带任何协议头,你发啥它就传啥字节流。客户端怎么解,完全取决于你们约定的协议。
- 纯文本消息建议结尾加换行符
"\n",方便客户端用readline()类方法读取(如 PHP 的fgets()、Node.js 的readline模块) - 二进制协议需严格按长度字段打包,避免粘包;可配合
Worker::$protocol = 'YourProtocol'自定义解析器 - 中文等 UTF-8 字符要确保客户端也用 UTF-8 解码,否则显示乱码——这不是 Workerman 的问题,而是两端编码不一致
- 不要直接
send()PHP 数组或对象,必须序列化:$connection->send(json_encode($data, JSON_UNESCAPED_UNICODE)."\n");
最容易被忽略的是连接存活判断和协议对齐——发得再快,对方收不到或解不开,等于白忙。TCP 不像 WebSocket 有内建帧格式,每一步都得自己兜底。

















