Workerman中捕获连接异常需协同onError、onClose及协议类内部try/catch:onError专捕socket层错误(如ECONNRESET),onClose负责资源清理,decode等解析异常须手动捕获处理。

Workerman 5.2.3 中,自定义协议本身不直接“捕获连接异常”,因为连接层面的异常(如客户端突然断网、RST 包、SYN 超时、握手失败等)由底层 TCP 栈和 Workerman 的连接管理机制统一处理,不在自定义协议类(input/decode/encode)中触发。真正能感知并响应连接异常的位置,是 Worker 实例注册的事件回调,尤其是 onError 和 onClose。
要可靠捕获连接异常,需从三个层次协同处理:
连接建立与通信过程中的异常(推荐主用 onError)
onError 是 Workerman 提供的唯一专门用于捕获连接级错误的回调,它会在 socket 层发生错误时被触发(例如:ECONNRESET、EPIPE、ETIMEDOUT、ENOTCONN 等),且早于 onClose。
$worker->onError = function ($connection, $code, $msg) {
// $code 是系统 errno(如 104 表示 Connection reset by peer)
// $msg 是对应错误描述(如 'Connection reset by peer')
\Workerman\Worker::log("Connection error [{$code}]: {$msg} from " . $connection->getRemoteIp());
// 可选:记录到自定义日志、推送告警、清理关联资源
// 注意:此时 $connection 仍有效,可调用 $connection->close()(但通常已断开)
};✅ 适用场景:
- 客户端强制关闭(kill 进程、拔网线)
- 防火墙中断连接
- TLS 握手失败(若用 SSL)
- 协议解析前就发生的 I/O 错误
⚠️ 注意:onError 不会因 input() 返回 false 或解包失败而触发——那是应用层逻辑错误,应由你自行在 decode 或 onMessage 中 try/catch 处理。
连接被动关闭(配合 onClose 做兜底)
onClose 在连接被对端正常关闭(FIN)或 onError 后自动触发,是清理资源的最后机会:
$worker->onClose = function ($connection) {
$ip = $connection->getRemoteIp();
// 清理该连接绑定的用户状态、房间信息、心跳定时器等
unset($_SESSION[$ip]); // 示例:若你用连接 ID 做 session key
\Workerman\Worker::log("Connection closed gracefully or after error: {$ip}");
};✅ 作用:
- 释放内存引用
- 通知其他客户端“某人下线”
- 更新在线人数统计
自定义协议内部的解析异常(需手动 try/catch)
如果你的 decode() 方法里做了 JSON 解析、unpack 字节、校验 CRC 等操作,这些属于应用层解包失败,不属于连接异常,必须自己捕获:
class MyProtocol implements \Workerman\Protocols\ProtocolInterface
{
public static function decode($buffer)
{
try {
// 假设协议头4字节为长度,后跟 JSON body
if (strlen($buffer) < 4) return null;
$len = unpack('N', $buffer)[1];
if (strlen($buffer) < 4 + $len) return null;
$json = substr($buffer, 4, $len);
$data = json_decode($json, true);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception('Invalid JSON in packet');
}
return $data;
} catch (\Exception $e) {
// 记录解析错误,但不关闭连接(除非你要求严格容错)
\Workerman\Worker::log('Decode failed: ' . $e->getMessage());
return null; // 返回 null 表示丢弃该包
}
}
}❌ 不要在这里 throw 未捕获异常,否则会导致 Workerman 进程崩溃(除非你已配置全局异常处理器)。
补充:确保错误可见的必要配置
- 开启 Workerman 全局日志:
\Workerman\Worker::$logFile = '/path/to/workerman.log';
- 检查
onWorkerStart是否静默失败(导致onError未注册):
在onWorkerStart中加var_dump("worker started");并查workerman.log,确认回调已生效。
不复杂但容易忽略:onError 是连接异常的第一道防线,onClose 是善后出口,协议类里的异常要自己兜住。三者分工明确,各司其职。

















