为什么不能同时绑定到0.0.0.0:80和192.168.1.1:80?

我的Pythontesting代码:

import socket s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s1.bind(('192.168.1.1', 80)) s1.listen(5) s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s2.bind(('0.0.0.0', 80)) s2.listen(5) 

我得到这个错误:

 fpemud-workstation test # ./test.py Traceback (most recent call last): File "./test.py", line 11, in <module> s2.bind(('0.0.0.0', 80)) File "/usr/lib64/python2.7/socket.py", line 224, in meth return getattr(self._sock,name)(*args) socket.error: [Errno 98] Address already in use 

192.168.1.1是我的eth0接口的ip地址。
我认为0.0.0.0:80和192.168.1.1:80应该能够共存。
使用dst-addr 192.168.1.1的数据包进入套接字s1,使用其他dst-addr的数据包进入套接字s2。

您不能绑定到端口80上的0.0.0.0:80和任何其他IP,因为0.0.0.0覆盖了机器上存在的每个IP,包括192.168.1.1地址。 这并不意味着“任何其他目标地址”,这意味着“这个盒子上的所有接口”。

因为这是一个矛盾的方面。 0.0.0.0表示“接受来自任何本地IP地址的连接”。 192.168.1.1表示“只接受连接到192.168.1.1的连接”。 如果有人连接到192.168.1.1,你预期会发生什么?

尽管还有其他的答案,这应该是可能的 – 只是bind工作的方式是依赖于实现的。

例如,在Windows上,您的代码可能会正常工作。 在一些* nix操作系统上,我相信你可以通过设置SO_REUSEADDR套接字选项来工作。 在Linux上,我已经能够使用SO_REUSEPORT套接字选项使其工作,但只能在内核版本3.9或更高版本上使用。

不幸的是SO_REUSEPORT属性在当前版本的python中不直接支持,所以我们必须手动定义它。

基本上你的代码应该是这样的:

 # This adds support for the SO_REUSEPORT constant if not already defined. if not hasattr(socket, 'SO_REUSEPORT'): socket.SO_REUSEPORT = 15 s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) s1.bind(('192.168.1.1', 80)) s1.listen(5) s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) s2.bind(('0.0.0.0', 80)) s2.listen(5)