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

时间:2013-06-25 21:23:09

标签: python linux sockets

我的python测试代码:

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。

3 个答案:

答案 0 :(得分:13)

您无法绑定到0.0.0.0:80和端口80上的任何其他IP,因为0.0.0.0涵盖了计算机上存在的每个IP,包括您的192.168.1.1地址。它并不代表任何其他目的地地址,它表示此框中的所有接口都是&#39;。

答案 1 :(得分:1)

因为这是一个矛盾的术语。 0.0.0.0表示“接受来自任何本地IP地址的连接”。 192.168.1.1表示“仅接受发送到192.168.1.1的连接”。如果有人连接到192.168.1.1,您期望发生什么?

答案 2 :(得分:1)

尽管其他答案已经说过,但这应该是可行的 - 只是bind的工作方式依赖于实现。

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

不幸的是,当前版本的python并不直接支持SO_REUSEPORT属性,因此我们必须手动定义它。

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

# 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)