这篇博客是为了填上篇的坑。内容是关于 netstat
的 bug(至少我认为是 bug) 及应对方法。
尽量准确地描述这个 bug:在有进程 fork()
、导致父子进程都占用同一个端口的情况下,netstat
不显示子进程对该端口的占用。
测试代码及运行方法详见上篇博客,这里不再赘述。直接贴 bug 现象:
# netstat -tlnp | grep 1111 tcp 0 0 0.0.0.0:1111 0.0.0.0:* LISTEN 6394/./fork_test.out
程序 fork()
产生了子进程 rsyncd,主进程 fork_test.out 和子进程 rsyncd 都占用了相同的监听端口,但是 netstat
的查看结果却忽略了 rsyncd,只显示 fork_test.out 对端口的占用。
只是理论上这么说,似乎显得论据不足。ss
/lsof
也可以显示端口占用情况,作为对比,这两个工具都能显示子进程 rsyncd 对端口的占用:
# ss -tlnp | grep 1111 LISTEN 0 10 *:1111 *:* users:(("rsync",27258,3),("fork_test.out",27249,3)) # lsof -i tcp:1111 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME fork_test.out 27249 nostalgia 3u IPv4 95394963 0t0 TCP *:lmsocialserver (LISTEN) rsync 27258 nostalgia 3u IPv4 95394963 0t0 TCP *:lmsocialserver (LISTEN)
可以看出,相比 netstat
,ss
和 lsof
都能完整地显示端口占用情况。
会不会是自己使用 netstat
时,参数使用有误,导致显示结果不全呢?遗憾的是,man netstat
并未找到相应的参数。相反,却看到下面一句说明:
This program is obsolete. Replacement for netstat is ss. Replacement for netstat -r is ip route. Replacement for netstat -i is ip -s link. Replacement for netstat -g is ip maddr.
不过,也有人遇到了同样的情形,而 netstat
显示结果却是正常的。比如,可以看看 StackOverflow 上的这个链接。
个人猜测,可能那 netstat
的版本或 kernel 版本有关。显示有误的版本信息收集如下:
# uname -r 3.2.0-24-generic-pae # netstat --version net-tools 1.60 netstat 1.42 (2001-04-15) Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang and others +NEW_ADDRT +RTF_IRTT +RTF_REJECT +FW_MASQUERADE +I18N AF: (inet) +UNIX +INET +INET6 +IPX +AX25 +NETROM +X25 +ATALK +ECONET +ROSE HW: +ETHER +ARC +SLIP +PPP +TUNNEL +TR +AX25 +NETROM +X25 +FR +ROSE +ASH +SIT +FDDI +HIPPI +HDLC/LAPB +EUI64
# uname -r 3.12.9-2-ARCH # netstat --version net-tools 2.10-alpha Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang, Brian Micek and others +NEW_ADDRT +RTF_IRTT +RTF_REJECT +FW_MASQUERADE -I18N AF: (inet) +UNIX +INET +INET6 +IPX +AX25 +NETROM +X25 +ATALK +ECONET +ROSE -BLUETOOTH HW: +ETHER +ARC +SLIP +PPP +TUNNEL -TR +AX25 +NETROM +X25 +FR +ROSE +ASH +SIT +FDDI +HIPPI +HDLC/LAPB +EUI64
启示:
用 netstat
查看端口占用,结果可能不可靠。可以考虑用 ss
/lsof
替代。
[…] 这该如何解释呢?我直接说我总结的结论好了。这似乎是 netstat 的 bug:在有进程 fork()、导致父子进程都占用同一个端口的情况下,netstat 不显示子进程对该端口的占用。对于这个问题,我会专门写篇博客。 […]