workerman仅中转信令,不参与stun/turn穿透;stun/turn由浏览器在rtcpeerconnection初始化时直连专用服务,需正确配置iceservers并确保https、udp可达及turn凭据动态生成。

Workerman 本身不处理 STUN/TURN,只负责信令中转
STUN/TURN 是 WebRTC 客户端(浏览器)在 RTCPeerConnection 初始化时主动连接并使用的网络服务,Workerman 作为 PHP 后端框架,**完全不参与 NAT 穿透过程**。它既不会启动 STUN 服务器,也不能代理或转发 STUN Binding 请求——这类 UDP 请求必须由专用 C/C++ 或 Rust 实现的服务(如 coturn)响应。
常见误解是“让 Workerman 帮忙打洞”,实际它只做三件事:
• 接收前端发来的 offer/answer 和 ice-candidate
• 按房间或用户 ID 转发给目标客户端
• 不修改、不解析、不缓存这些内容(避免引入延迟或格式错误)
如何配置 RTCPeerConnection 才能让 STUN/TURN 生效
穿透是否成功,取决于前端创建 RTCPeerConnection 时传入的 iceServers 配置,和客户端网络环境。Workerman 对此零干预,但你必须确保:
-
iceServers数组里至少含一个可用 STUN 地址,例如{ urls: "stun:stun.l.google.com:19302" };生产环境建议自建 coturn 并启用 TLS/DTLS - 若需 TURN 备份(比如企业内网、对称 NAT 场景),必须显式提供
urls、username、credential,且 credential 需动态生成(不能硬编码) - 不要把 TURN 的
urls写成ws://或wss://——那是 WebSocket 中继,不是 TURN;TURN 必须用turn:xxx或turns:xxx - 前端调用
pc.addIceCandidate()时,必须确保 candidate 字符串完整(含a=行),否则oniceconnectionstatechange会卡在checking
为什么信令消息里看不到 STUN/TURN 流量
因为 STUN/TURN 流量根本不会经过 Workerman:
- STUN Binding Request/Response 是 UDP 包,直连 STUN 服务器 IP:Port,浏览器自动发出,不走 WebSocket
- TURN Allocate 请求也走 UDP(或 TCP/TLS),由
RTCPeerConnection底层触发,Workerman 无感知 - 你唯一能在 Workerman 日志里看到的,只有客户端通过 WebSocket 发来的
ice-candidate字符串——它只是“我刚才从 STUN 收到了这个公网地址”,不是穿透本身 - 如果
onicecandidate一直没触发,说明 STUN 请求失败或被防火墙拦截,此时应检查浏览器控制台的chrome://webrtc-internals,而不是改 Workerman 代码
容易被忽略的关键点
穿透失败往往卡在最基础的地方:
- 前端页面没走 HTTPS(或非
localhost的 HTTP),getUserMedia被拒,后续所有流程都起不来 - Workerman 的 WebSocket 服务用了
ws://,但浏览器要求信令必须加密(wss://),导致连接直接断开,offer根本发不出去 - 客户端网络策略禁止 UDP(如某些校园网、国企内网),即使配了 TURN,
RTCPeerConnection也会因无法建立 relay 连接而 fallback 失败 -
iceTransportPolicy被设为"relay"却没配 TURN,连接将永远卡在new或checking
穿透逻辑全在浏览器里跑,Workerman 只是那个递纸条的人——纸条写什么、能不能送到、对方看不看得懂,它一个都管不了。











