客户端连接不上Workerman怎么排查_防火墙和端口检测步骤【操作】

2次阅读

确认workerman进程是否真正在监听端口,需用ss -tuln | grep :端口验证内核监听状态;若仅显示127.0.0.1则外部不可访问,应绑定0.0.0.0;ps aux需见worker进程,无则检查onWorkerStart异常;客户端须telnet服务器真实IP,同时排查安全组、防火墙、docker绑定及TIME_WAIT问题。

客户端连接不上Workerman怎么排查_防火墙和端口检测步骤【操作】

确认 Workerman 进程是否真正在监听端口

很多人看到 php start.php start 输出 “Start success”,就以为服务起来了,其实可能只是主进程启动了,Worker 子进程因配置错误、代码异常或权限问题根本没起来。最直接的验证方式是查系统级监听状态,而不是只看 Workerman 日志。

  • linux/macos 上用 ss -tuln | grep :2345(把 2345 换成你实际监听的端口),有输出才说明内核确实在监听;没有输出,90% 是 Workerman 没跑起来或监听失败
  • 如果看到 127.0.0.1:2345 但看不到 *:2345,说明 Workerman 绑定了 localhost,外部客户端连不上——得检查 $worker->listen('tcp://0.0.0.0:2345')'tcp://*:2345',不能写成 'tcp://127.0.0.1:2345'
  • Workerman 启动后,ps aux | grep WorkerMan 应该能看到至少一个 WorkerMan: worker process 进程;只有 master process 而没有 worker,基本是 onWorkerStart 抛了未捕获异常,去 workerman.log 最末尾找 Fatal ErrorException

本地 telnet 能通 ≠ 客户端能连,重点看目标 IP 和网络路径

在服务器上 telnet 127.0.0.1 2345 成功,只说明本机 loopback 通;客户端连不上,大概率卡在中间某一层:本机防火墙、云厂商安全组、NAT 网关、甚至客户端所在局域网出口策略。

  • 从客户端机器直接执行 telnet your-server-ip 2345 —— 这步必须做,不能只信服务器上的测试
  • 云服务器(阿里云/腾讯云等)务必进控制台检查「安全组规则」,确认入方向放行了对应端口(协议选 TCP,源 IP 如果是未知客户端,暂时设为 0.0.0.0/0 测试)
  • 本地开发用 VirtualBox / WSL / Docker 时,宿主机 windows/macOS 的防火墙常默认拦截外来连接;Windows 上临时关掉「Windows Defender 防火墙」或加入例外规则,macOS 查 pfctl -sr 或系统偏好设置 → 防火墙
  • 如果 Workerman 跑在 Docker 容器里,除了 -p 2345:2345,还得确认容器内监听的是 0.0.0.0:2345,不是 127.0.0.1:2345(后者在容器里也只响应 localhost)

Workerman 日志里没报错,但连接被静默拒绝?查 SO_REUSEADDR 和 TIME_WAIT

端口看似空闲,但系统还没彻底释放上次连接的 socket,新进程 bind 会失败,Workerman 却可能不报错、也不监听——此时客户端 Connection refused,但 ss -tuln 看不到端口,日志也干净。

  • 启动前手动清理:先 killall php(或按 PID 杀掉所有 Workerman 进程),再 ss -tan | grep :2345 看是否有 TIME_WAIT 状态残留;大量存在说明连接频繁断开,需调优
  • 在 Workerman 启动代码里显式设置 $worker->reusePort = true;(PHP 7.0+ Linux),避免端口争抢;老版本或 Windows 可设 $worker->soReusePort = true;(需内核支持)
  • 别依赖 start.php restart,它只是 stop + start,stop 不一定杀干净;生产环境改用 start.php stop && sleep 1 && start.php start 更稳妥

客户端连上又立刻断开?检查协议握手和心跳逻辑

Workerman 默认是裸 TCP,客户端发数据前没做任何协议协商。如果客户端期望 http 握手、websocket 升级,或服务端开了 heartbeat_idle_time 但客户端没发心跳,就会秒断。

  • nc -v your-server-ip 2345 手动连,敲几个字符回车——如果立刻断开,说明服务端代码里可能写了 $connection->close()onMessage 外触发,或 onConnect 里抛了异常
  • 检查 onMessage 是否对非法数据直接 return 而没 $connection->send(),某些客户端库会把无响应当成异常断连
  • 若启用了心跳($worker->ping_interval = 30;),客户端必须每 ping_interval - ping_not_response_limit 秒内发一次任意数据,否则 Workerman 主动 close;调试阶段可先注释掉心跳相关配置
  • wireshark 抓包看三次握手是否完成、SYN/ACK 是否返回、是否有 RST 包——这是绕过所有应用层日志的终极手段

真正卡住排查的,往往是“明明端口开着、日志没报错、telnet 也通,但就是连不上”。这时候得一层层剥:先确认客户端真实发出的 SYN 到了哪一层,再反推是防火墙拦了、路由丢了、还是 Workerman 根本没收到连接请求。别急着改代码,先让网络路径自己说话。

text=ZqhQzanResources