必须写成[::]才能同时监听ipv4和ipv6,0.0.0.0或空字符串仅支持ipv4;swoole需显式绑定[::]启用双栈,缺方括号或误用swoole_sock_tcp6会导致ipv6连接失败。

监听地址必须写成 [::],不能用 0.0.0.0 或空字符串
服务端要真正接受 IPv6 连接,关键在启动时绑定的地址。Swoole 不会自动将 0.0.0.0 映射到 IPv6,也不支持 ""(空字符串)这种模糊写法。必须显式指定 IPv6 通配地址:[::]。
常见错误是照搬 IPv4 写法,比如 new Swoole\Http\Server('0.0.0.0', 8080),结果只监听 IPv4;或者误写成 '::'(缺方括号),导致 bind(): Invalid argument 错误。
-
new Swoole\Http\Server('[::]', 8080)—— 正确,双栈监听(IPv4 + IPv6) -
new Swoole\WebSocket\Server('[::]:8081')—— 正确,WebSocket 同理 -
new Swoole\Server('[::]', 9501, SWOOLE_SOCK_TCP6)—— 可选,强制仅 IPv6(不推荐,除非明确隔离)
SWOOLE_SOCK_TCP6 是可选标记,但多数场景下不用加
SWOOLE_SOCK_TCP6 表示“仅创建 IPv6 socket”,但它会拒绝所有 IPv4 连接,包括 IPv4-mapped IPv6 地址(如 ::ffff:127.0.0.1)。实际部署中,双栈更实用,而 [::] 绑定默认就启用双栈支持,无需额外 flag。
加了 SWOOLE_SOCK_TCP6 反而容易出问题:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 客户端用 IPv4 地址连不上,报
Connection refused - 某些容器环境(如 Docker 默认 bridge)不转发 IPv6,加了反而全不可用
- ThinkPHP 的
swoole.php配置里若硬编码'sock_type' => SWOOLE_SOCK_TCP6,会导致host设为[::]也无效
客户端连接 IPv6 地址必须用方括号包裹,且禁用 DNS 解析
PHP 原生 socket 函数(如 stream_socket_client)不识别带协议的 URI,直接传 ws://[::1]:8080 会触发 getaddrinfo failed。你得手动拆解并构造合法 socket URI。
正确做法:
- 提取 host 和 port:把
ws://[::1]:8080拆成[::1]和8080 - 拼 socket 地址:
tcp://[::1]:8080(不是ws://) - 调用时加选项禁用 DNS:
['socket' => ['bindto' => '0.0.0.0:0']]不够,必须设'dns_disable' => true(仅部分版本支持),更稳妥的是直接传解析后的 IP - WebSocket 握手头(
Upgrade: websocket等)仍需手动发送,Swoole 客户端不自动处理
验证是否真在监听 IPv6:别只信 netstat,要看 ss -tlnp 和日志
netstat -tlnp | grep :8080 在较新系统上可能不显示 IPv6 监听项,尤其当内核未启用 IPv6 或模块未加载时。优先用 ss -tlnp:
ss -tlnp | grep ':8080'
# 应看到类似:
tcp LISTEN 0 128 [::]:8080 *:* users:(("php",pid=12345,fd=8))
另外,Swoole 启动后日志第一行会明确打印监听地址。如果看到 listen 0.0.0.0:8080,说明配置没生效;看到 listen [::]:8080 才算到位。Docker 用户还需确认容器启动时加了 --sysctl net.ipv6.conf.all.disable_ipv6=0,否则即使代码写对,内核也会静默丢弃 IPv6 bind 请求。










