绑定失败,地址正在使用:无法将 TCP 端口同时用于源和目标?

绑定失败,地址正在使用:无法将 TCP 端口同时用于源和目标?

我正在调试无法启动的 Hadoop DataNode。我们在机器上使用 saltstack 和 elasticsearch。

Hadoop DataNode 错误非常明显:

java.net.BindException: Problem binding to [0.0.0.0:50020]    
java.net.BindException: Address already in use; 
      For more details see:  http://wiki.apache.org/hadoop/BindException

[...]

Caused by: java.net.BindException: Address already in use

[...]

(ExitUtil.java:terminate(124)) - Exiting with status 1

lsof -i -n对于端口 50020 来说它已被使用,但仅作为源端口而不是目标端口:

salt-mini 1733          root   25u  IPv4  17452      0t0  TCP xx.xx.132.72:50020->xx.xx.132.20:4505 (ESTABLISHED)
java      2789 elasticsearch 2127u  IPv6   9808      0t0  TCP xx.xx.132.72:50020->xx.xx.132.55:9300 (ESTABLISHED)

但是 0.0.0.0 上的绑定似乎不起作用:

root@host:~# nc -l 50020
nc: Address already in use

这是故意的吗?当端口已被用作源端口时,是否不允许绑定到 0.0.0.0?没有任何东西在监听套接字 - 我真的不知道为什么它不应该工作。

乌班图14.04:

root@host:~# uname -a
Linux host 4.2.0-19-generic #23~14.04.1-Ubuntu SMP Thu Nov 12 12:33:30 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

答案1

50020 是源端口还是目标端口并不重要:如果已声明,则已声明。

我认为需要在 49152 - 65535 范围内的特定端口上启动服务是一个错误,因为这些是 IANA 定义的临时端口。许多 Linux 发行版将高于 32768 的端口视为临时端口。您可以使用以下命令查看当前的临时端口范围:

cat /proc/sys/net/ipv4/ip_local_port_range

任何应用程序都可能只使用临时范围内的端口,因此不能保证特定端口始终空闲。最好选择 1024 到 32767 之间未使用的端口。

请参阅一些介绍临时端口

如果您想更改临时范围以满足 Hadoop DataNode 要求,您可以通过编辑/etc/sysctl.conf并按以下方式设置一行来实现:

net.ipv4.ip_local_port_range=56000 65000

编辑:感谢 @mr.spuratic,他间接指出,使用足够新的内核(更改于 2010 年 5 月提交),可以对该范围进行例外处理。建议这样做,因为玩弄该范围本身就是一个相当大的变化。

sysctl -w net.ipv4.ip_local_reserved_ports = 50020, 50021

引用自文档/网络/ip-sysctl.txt

ip_local_reserved_ports - list of comma separated ranges

Specify the ports which are reserved for known third-party
applications. These ports will not be used by automatic port
assignments (e.g. when calling connect() or bind() with port
number 0). Explicit port allocation behavior is unchanged.

The format used for both input and output is a comma separated
list of ranges (e.g. "1,2-4,10-10" for ports 1, 2, 3, 4 and
10). Writing to the file will clear all previously reserved
ports and update the current list with the one given in the
input.

Note that ip_local_port_range and ip_local_reserved_ports
settings are independent and both are considered by the kernel
when determining which ports are available for automatic port
assignments.

You can reserve ports which are not in the current
ip_local_port_range, e.g.:

$ cat /proc/sys/net/ipv4/ip_local_port_range
32000   60999
$ cat /proc/sys/net/ipv4/ip_local_reserved_ports
8080,9148

although this is redundant. However such a setting is useful
if later the port range is changed to a value that will
include the reserved ports.

Default: Empty

答案2

我认为这是正常行为,如果端口被使用,它就会被使用。来源或目的地并不重要。

0.0.0.0 意味着您尝试侦听该端口的所有网络地址。因此,如果您有 2 个 IP 地址,例如 192.168.1.20 和 10.4.2.1,则如果您指定 IP 地址,则可以使用该端口两次

答案3

但是 0.0.0.0 上的绑定似乎不起作用:

root@host:~# nc -l 50020
nc: Address already in use

这是故意的吗?当端口已被用作源端口时,是否不允许绑定到 0.0.0.0?没有任何东西在监听套接字 - 我真的不知道为什么它不应该工作。

这是完全正常的。特殊的 IP 地址 0.0.0.0 表示该机器响应的“任何”互联网协议地址,这意味着它绑定到系统上的每个 IP 地址。每个 TCP 连接都是双向有状态连接,源/目标实际上仅在初始握手时才有意义。对您来说真正重要的是连接端的端口号。

从 IP 堆栈的角度考虑您的问题。它在 xx.xx.132.72:50020 上有一个现有的 TCP 连接,并且您正在尝试将侦听套接字绑定到 0.0.0.0:50020。此特殊地址扩展为包含 xx.xx.132.72:50020,但在使用时失败。如果它没有失败,入站到该地址的 IP 数据包如何识别它是被传递到您的侦听套接字还是预先存在的连接?当然,您可以设想一种允许多个套接字共享一个端口的方案,但是您已经重新设计了端口首先要解决的问题。

您的侦听套接字可能对端口号有更好的声明,因为它需要在可靠的位置进行访问,因此您需要更改其他应用程序端口。如果不可配置,只需停止其他应用程序,启动您的服务器,然后重新启动该应用程序,该应用程序将使用不同的可用源端口进行传出连接,并且不再与您的服务器冲突。

相关内容