Module: Lich::Common::ReusableTCPServer

Defined in:
documented/common/reusable_tcp_server.rb

Overview

Factory for creating TCP server sockets with SO_REUSEADDR set before binding.

Ruby's TCPServer.new calls bind and listen internally during construction, so any setsockopt call made after construction is too late - the port is already bound without the reuse flag. This causes "Address already in use" failures when restarting quickly because the kernel holds the port in TIME_WAIT for ~60 seconds.

This module separates socket creation from binding so that SO_REUSEADDR takes effect before the port is claimed.

Examples:

Create a reusable listener on a specific port

server = Lich::Common::ReusableTCPServer.create('127.0.0.1', 8000)
client = server.accept

See Also:

Since:

  • 5.12.0

Class Method Summary collapse

Class Method Details

.create(host, port, backlog: 1) ⇒ Socket

Creates a TCP server socket with SO_REUSEADDR enabled before binding.

Parameters:

  • host (String)

    the address to bind to (IPv4, IPv6, or hostname)

  • port (Integer)

    the port to listen on

  • backlog (Integer) (defaults to: 1)

    the listen queue depth (default: 1)

Returns:

  • (Socket)

    a bound, listening socket ready for accept

Raises:

  • (Errno::EADDRINUSE)

    if the port is unavailable even with SO_REUSEADDR

  • (SocketError)

    if the address is invalid

Since:

  • 5.12.0



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'documented/common/reusable_tcp_server.rb', line 32

def self.create(host, port, backlog: 1)
  address = Addrinfo.tcp(host, port)
  server = Socket.new(address.afamily, :STREAM)
  begin
    server.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(backlog)
    server
  rescue
    server.close rescue nil
    raise
  end
end