Linux tcp 服务器无法绑定(bind)到 close_wait 端口

标签 linux networking server tcp

我试图让 tcp 服务器绑定(bind)到 close_wait 端口,但它导致了 Errno::EADDRINUSE 错误。

我创建了一个监听端口 55555 的 tcp 服务器。然后客户端连接到该服务器。在一些操作之后,运行 ss -at | grep 55555.

# ss -at | grep 55555
LISTEN     0      128                     *:55555                    *:*
FIN-WAIT-2 0      0               127.0.0.1:55555            127.0.0.1:16413
CLOSE-WAIT 0      0               127.0.0.1:16413            127.0.0.1:55555

我尝试绑定(bind)端口 16413,它导致了 Errno::EADDRINUSE 错误。 但是如果我连接到 ESTAB 套接字,套接字可以绑定(bind)到端口(例如下面的 22385)。

# ss -at | grep 55555
LISTEN     0      128                     *:55555                    *:*
ESTAB      0      0               127.0.0.1:22385            127.0.0.1:55555
ESTAB      0      0               127.0.0.1:55555            127.0.0.1:22385 

通过 ruby​​ 的一些脚本来重现该问题。

tcp_server_close_wait.rb

require 'socket'

server = TCPServer.new 55555 # Server bind to port 2000
loop do
  client = server.accept    # Wait for a client to connect
  client.puts "Hello !"
  client.puts "Time is #{Time.now}"
  client.shutdown(Socket::SHUT_WR)
end

tcp_server.rb

require 'socket'

server = TCPServer.new 55555 # Server bind to port 2000
loop do
  client = server.accept    # Wait for a client to connect
  client.puts "Hello !"
  client.puts "Time is #{Time.now}"
  client.close
end

tcp_client.rb

require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 55555, '127.0.0.1' )
socket.connect( sockaddr )
res = socket.read
puts res

sleep 10000

** tcp_bind.rb **

require 'socket'

# use Addrinfo
socket = Socket.new(:INET, :STREAM, 0)
socket.bind(Addrinfo.tcp("0.0.0.0", ARGV[0].to_i))

创建 close_wait 绑定(bind)。

  1. 运行 ruby tcp_server_close_wait.rb

  2. 运行 ruby tcp_client.rb

  3. 运行 ss -at | grep 55555 查找客户端端口

  4. 运行 ruby tcp_bind.rb $client_port

创建 ESTAB 绑定(bind)。 1. 运行 ruby tcp_server.rb

  1. 运行 ruby tcp_client.rb

  2. 运行 ss -at | grep 55555 查找客户端端口

  3. 运行 ruby tcp_bind.rb $client_port

最佳答案

我使用 C 程序对 Linux 4.4.74-18.20 版重复了相同的测试。

我得到的结果与 OP 不同。

当 SO_REUSEPORT 被禁用时,两个端口的绑定(bind)都失败了:

  • 建立TCP连接的客户端端口(ESTAB)
  • 半开TCP连接(CLOSE-WAIT)的客户端端口

当启用 SO_REUSEPORT 时(对于所有套接字),两个端口的绑定(bind)成功。

参见 socket(7) man page获取有关 SO_REUSEPORT 的更多信息。

关于Linux tcp 服务器无法绑定(bind)到 close_wait 端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51036790/

相关文章:

ubuntu docker 镜像 18.04 的 Linux 头文件

linux - 内核驱动程序 - ZedBoard - Linux 在访问地址后挂起

ruby - 为什么crontab不能用ruby?

javascript - NodeJS 服务器更改 JSON 对象的键名

linux - 删除或替换第一行 3500 个 php 文件

node.js - 如何让 NodeJs 项目在端口 3000 上可公开访问?

linux - 如何在 CentOS 5.8 中重新编译 asterisk?

networking - websocket 可以耗尽网络服务器的连接池吗

php - 计算给定网络中可用子网的数量

Android获取热点提供设备的IP地址