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

kei*_*u4U 3 hadoop

我正在调试无法启动的 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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

root@host:~# nc -l 50020
nc: Address already in use
Run Code Online (Sandbox Code Playgroud)

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

Ubuntu 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
Run Code Online (Sandbox Code Playgroud)

joe*_*epd 11

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

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

cat /proc/sys/net/ipv4/ip_local_port_range
Run Code Online (Sandbox Code Playgroud)

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

请参阅有关临时端口的一些介绍。

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

net.ipv4.ip_local_port_range=56000 65000
Run Code Online (Sandbox Code Playgroud)

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

sysctl -w net.ipv4.ip_local_reserved_ports = 50020, 50021
Run Code Online (Sandbox Code Playgroud)

引用自Documentation/networking/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
Run Code Online (Sandbox Code Playgroud)

  • `ip_local_port_range` 是在繁忙的服务器上小心挥舞的大锤子。使用`ip_local_reserved_ports` 的当代(linux-2.6.35 之后)方式允许[枚举麻烦的端口](http://unix.stackexchange.com/questions/15511/how-do-i-reserve-ports-for -我的应用程序)。 (2认同)