服务先监听 [::]:8000,再监听 0.0.0.0:8000 时报 EADDRINUSE,ss 里只看到一条 tcp6 的 LISTEN。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,Linux 的 net.ipv6.bindv6only 默认是 0,绑定 :: 会同时接管 IPv4 的同一端口。两个 socket 抢同一个端口,第二个 bind 必然失败。
「双栈监听冲突」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
sysctl net.ipv6.bindv6only ss -tlnp | grep 8000
权限不要一口气开到最大,先加到够用再往上试,范围小才好收。把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。
改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
具体做法是,显式设置 IPV6_V6ONLY 为 1;或者只监听 :: 并接受映射地址;要分开处理就建两个独立 socket;改完确认 sysctl 的实际取值。
最后用这个标准收尾,设了 IPV6_V6ONLY 后两个 socket 能同时 bind,v4 和 v6 地址都能访问。
