Tcp сервер Linux не может привязаться к порту close_wait - PullRequest
0 голосов
/ 26 июня 2018

Я пытался разрешить tcp-серверу связываться с портом close_wait, но это вызвало ошибку Errno::EADDRINUSE.

Я создал tcp сервер, который прослушивает порт 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

Я пытался привязать порт 16413, это вызвало ошибку Errno::EADDRINUSE. Но если я подключился к 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 

Некоторые сценарии 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

1 Ответ

0 голосов
/ 26 июня 2018

Я повторил тот же тест с версией Linux 4.4.74-18.20, используя программы на Си.

Я получил результаты, отличные от ОП.

Когда SO_REUSEPORT был отключен, привязка не удалась для обоих портов:

  • порт клиента установленного TCP-соединения (ESTAB)
  • порт клиента полуоткрытого TCP-соединения (CLOSE-WAIT)

Когда был включен SO_REUSEPORT (для всех сокетов), успешное связывание для обоих портов.

См. Справочную страницу socket (7) для получения дополнительной информации о SO_REUSEPORT.

...