Struggling to make a TCP server based on new socket module using use the “reuseaddr” and “reuseport” options

I’m struggling to make the TCP server based on new socket module (from the doc) use the “reuseaddr” and “reuseport” options.

server(Addr, Port) ->  
   {ok, LSock} = socket:open(inet, stream, tcp),
   ok = socket:bind(LSock, #{family => inet,
                             reuseaddr => true,  %% this fails
                             reuseport => true,   %% this fails as well
                             port   => Port,
                             addr   => Addr}),
   ok = socket:listen(LSock),
   {ok, Sock} = socket:accept(LSock),
   {ok, Msg} = socket:recv(Sock),
   ok = socket:send(Sock, Msg),
   ok = socket:close(Sock),
   ok = socket:close(LSock).

I’d like to have a listening socket and 2 worker processes accepting connection on the same port (hence the reuseaddr).

What am i doing wrong?

1 Like

I’m not sure that reuseaddr and reuseport are part of sockaddr() type, but they are covered by socket_option() type. Try setting those options to true with socket:setopt/3 before binding the socket.

Also, according to Erlang -- Socket Usage those options must be set on OS level and used only with inet/inetv6 addresses.

1 Like

The main issue with your use of socket options is that reuseaddr and reuseport options have to be set prior to calling socket:bind/2. Try this:

{ok, LSock} = socket:open(inet, stream, tcp),
ok = socket:setopt(LSock, socket, reuseaddr, true),
ok = socket:setopt(LSock, socket, reuseport, true),
ok = socket:bind(LSock, #{family => inet, port => Port, addr => Addr}),

Secondly, if you need to have multiple worker processes doing the accept, you can pass the LSock to a pool of worker processes so that they are calling the socket:accept/1 on the same instance of LSock. If your idea was that the reuseaddr and reuseport will help you have multiple listening sockets open on the same address/port pair, that is not what those two options are for. These options are meant to allow your OS process to reconnect to the same address/port right after the process crashed that was previously bound to that address/port pair, so that the OS would release the socket and make it available for new binding immediately.