我有一个 Java 套接字服务器,它是使用“ localhost
”上的临时端口(与端口 0 绑定)创建的。但是,启动并运行后,netstat 显示有另一个进程在任何接口上侦听同一端口。
这是netstat
输出:
$ sudo netstat -n -a -p | grep 34797
tcp6 0 0 127.0.0.1:34797 :::* LISTEN 4210/java
tcp6 0 0 :::34797 :::* LISTEN -
使用后rpcinfo
,我确认是NFS nlockmgr
。我可以通过套接字服务器显式绑定到同一34797
端口来重现该问题。
仅适用于 NFS 服务使用的端口 ( rpc.mountd
、nlockmgr
)。如果我尝试对现有应用程序已绑定到任何接口上的端口执行相同的操作::
,则会导致绑定“ Address already in use
”错误,这正是我所期望的。
这对我来说是个问题,因为它弄乱了我正在运行的用于接收请求的服务。
我的问题是,为什么 NFS 服务如此特殊,为什么 Linux 允许这种情况发生(通过分配已在使用的临时端口)?
答案1
一般来说,您所经历的情况能当涉及到 IPv6 时,请保持常规。
在您的情况下,“任何地址”绑定是 IPv6 地址,而“localhost”地址绑定是 IPv4 地址。如果绑定到 IPv6“任意地址”的应用程序设置了IPV6_V6ONLY
套接字选项。
在 Linux 上,该选项还有一个系统范围的默认值,可以在其中查看和设置/proc/sys/net/ipv6/bindv6only
,其默认值0
使 IPv4 和 IPv6 共享 TCP/UDP 端口号空间。
127.0.0.1:34797 LISTEN
另请注意,您的套接字被标记的事实tcp6
与此目的无关,因为即使它由 IPv6 网络堆栈支持,它也被视为 IPv4 地址。这也是符合标准的行为。
您的情况的结果是,TCP 连接127.0.0.1:34797
将传送到您的java
应用程序,而到同一端口但到您计算机的任何 IPv6 地址的连接将传送到 NFS 锁定服务器。
至于为什么 NFS 开发人员选择这样做1我不知道,但这并不是 NFS 独有的:请参阅 OpenSSH 守护程序,它分别绑定 IPv4 和 IPv6 地址(默认情况下都是“任何地址”) 、IPv40.0.0.0
和 IPv6 ::
)。
此外,某些操作系统甚至不支持该IPV6_V6ONLY
选项(例如,它们不允许设置它),并且您在这些系统上获得的唯一行为是 IPv4 和 IPv6 之间的端口号空间完全分离,因此那里的应用程序必须如果要同时支持 IPv4 和 IPv6,请绑定同一端口两次。