0.0.0.0这个地址
0.0.0.0
是一个很好玩的IP地址。Wikipedia从Official meaning and use、Operating system specific uses、Other non-standard uses、Routing几个不同的角度对它进行了说明。它的用途远比作为参数传给bind
多。
几条说明中,最引人注目的还是Operating system specific uses
和 Other non-standard uses
。这两个条目说明,关于0.0.0.0
的含义和用途甚至没有一个统一的看法。它在不同操作系统下的表现也(可能)不同。
我们知道,bind
到0.0.0.0
相当于bind
到了所有的接口上。那么,在这些接口中,如果有的被占用,有的处于空闲状态,结果会如何呢?换句话说,这个bind
可以绑定端口,但不能绑定所有的端口。
用下面的python
代码在Linux和Windows上分别进行测试。这段代码尝试同时绑定127.0.0.1
和0.0.0.0
的TCP 33333端口,并打印进来的连接:
|
|
Linux下的结果
Linux直接甩了一个错误过来:
说明Linux不支持所谓partial bind
。先bind
0.0.0.0
再bind
127.0.0.1
会导致第二个bind
失败。老实说,这与我的预期也是一致的。一个操作只能完成一半,显然不能认为是成功的。
Windows下的结果
Windows下的结果就比较出乎意料了。这两个bind
都能成功,而且127.0.0.1
的bind
的优先级较0.0.0.0
高。用telnet
测试连接,发现不管是先绑定127.0.0.1
还是先绑定0.0.0.0
,telnet 127.0.0.1 33333
的连接总是被127.0.0.1
截获:
可能是127.0.0.1
的指称比0.0.0.0
更具体,就像路由表的匹配一样,Windows把两个方向都可以的流量分给了127.0.0.1
。但这种静默操作会导致很大的问题。如果你的程序监听了0.0.0.0
,而某个不知名的程序监听了127.0.0.1
,那你的程序就收不到来自127.0.0.1
的消息,而整个过程都不会有任何错误提示。
总结
总之,Linux和Windows对0.0.0.0
的处理确实是不太一样的。与Linux不同,Windows把路由优先级那一套搬到了bind
上面。如果bind
0.0.0.0
收不到localhost
的数据,不妨用resmon
看一下是不是有哪个进程bind
了localhost
,这种情况下Windows不会报错,只会静默地把你期望的包丢给另一个进程。