简体   繁体   English

Linux TCP服务器无法绑定到close_wait端口

[英]Linux tcp server can't bind to a close_wait port

I tried to let tcp server bind to a close_wait port, but it caused a Errno::EADDRINUSE error. 我试图让tcp服务器绑定到close_wait端口,但是它导致了Errno::EADDRINUSE错误。

I created a tcp server that listen on port 55555. Then client connected to that server. 我创建了一个侦听端口55555的tcp服务器。然后,客户端连接到该服务器。 After some ops, run ss -at | grep 55555 经过一些操作后,运行ss -at | grep 55555 ss -at | grep 55555 . 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

I tried to bind port 16413 , it caused a Errno::EADDRINUSE error. 我试图绑定端口16413 ,这导致了Errno::EADDRINUSE错误。 But if I connected to a ESTAB socket, the socket could bind to the port(such as 22385 below). 但是,如果我连接到ESTAB套接字,则该套接字可以绑定到端口(例如下面的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 

Some scripts by ruby to reproduce the problem. 一些脚本被ruby重现了问题。

tcp_server_close_wait.rb 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 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 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 ** ** 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))

Create close_wait bind. 创建close_wait绑定。

  1. run ruby tcp_server_close_wait.rb 运行ruby tcp_server_close_wait.rb

  2. run ruby tcp_client.rb 运行ruby tcp_client.rb

  3. run ss -at | grep 55555 运行ss -at | grep 55555 ss -at | grep 55555 to find client port ss -at | grep 55555查找客户端端口

  4. run ruby tcp_bind.rb $client_port 运行ruby tcp_bind.rb $client_port

Create ESTAB bind. 创建ESTAB绑定。 1. run ruby tcp_server.rb 1.运行ruby tcp_server.rb

  1. run ruby tcp_client.rb 运行ruby tcp_client.rb

  2. run ss -at | grep 55555 运行ss -at | grep 55555 ss -at | grep 55555 to find client port ss -at | grep 55555查找客户端端口

  3. run ruby tcp_bind.rb $client_port 运行ruby tcp_bind.rb $client_port

I repeated the same test with Linux version 4.4.74-18.20 by using C programs. 我使用C程序对Linux 4.4.74-18.20重复了相同的测试。

I got different results than OP. 我得到的结果与OP不同。

When SO_REUSEPORT was disabled, binding failed for both ports: 禁用SO_REUSEPORT时,两个端口的绑定均失败:

  • port of client of established TCP connection (ESTAB) 建立的TCP连接的客户端端口(ESTAB)
  • port of client of half open TCP connection (CLOSE-WAIT) 半开TCP连接的客户端端口(CLOSE-WAIT)

When SO_REUSEPORT was enabled (for all sockets), binding success for the both ports. 启用S​​O_REUSEPORT(针对所有套接字)后,两个端口的绑定成功。

See socket(7) man page for getting more information about SO_REUSEPORT. 有关获得有关SO_REUSEPORT的更多信息,请参见socket(7)手册页

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM