i have a very simple question, i want to create 20 children processes, each with the same listen socket, there are 2 methods i just want to know what differences between the two :
module(sup).
.....
start() ->
supervisor:start_link({local,?MODULE},?MODULE,[]).
%%%%%%%%%%%%%%%%%%
-------First Method---------
init([]) ->
Listen=gen_tcp:listen(....),
spawn(fun() ->start_children(20) end),
{ok,{{simple_one_for_one,5,1},[{child,{ChildModule,start,[Listen]},....}]}}.
%%%%%%%%%%%%%%%%%
start_children(N) ->
[supervisor:start_child(?MODULE, [])||_ <-lists:seq[1,N]],
ok.
this is a simple_one_for_one tree, i just create ONE listen socket and set it as an argument to each started process who will handle it later, i spawned a new process to run start_children/1
because this function call the supervisor and this later is in it's init/1
function and it can't start children before it's own start so the process will wait the initiation of the sup to call it, let's see the second method :
---------Second Method---------
init([]) ->
ChildSpecs=[{Id,{ChildModule,start,[fun createListenSocket/0]},....}||Id <-lists:seq[1,20]]
{ok,{{one_for_one,5,1},ChildSpecs}}.
%%%%%%%%%%%%%%%%%%%%
createListenSocket() ->
gen_tcp:listen(....).
This is a one_for_one tree and the sup created 20 children at start with 20 sockets:one socket for each child, so the question: are the two methods the same or are they differents ? if we consider that they are the same that means that a listen socket is just a variable and the special thing in a socket (listening for incoming connections) start when we run gen_tcp:accept/1
.
because if not, we have a case when 20 processes share the same listening socket in the first method.
EDIT :
ok i think that José had answer my question but his answer give me another problem :how to create many sockets with the same port and ip address in Erlang? because if i want run 20 sockets per node the ip is the local ip address and it's the same for all sockets and the port is the same too in the case that i want only one specified port for the application ? there in an option {reuseaddr, true}
as an argument to gen_tcp:listen
but it can be used just when we use the same port for different ip addresses and there is no reuseport
in Erlang so what's to do for that ?
CodePudding user response:
Disclaimer: this answer is about Linux.
No, these two approaches are not the same, the listen sockets are OS structures. One creates a listening socket and the other creates 20 listening sockets (or at least tries to, as the last 19 are going to fail unless you enable port reuse. You have a wonderful explanation about this option in this question).
You can check the listening sockets with sudo ss -punta | grep LISTEN
At OS level with multiple listen sockets, the load balancing of connections is performed by the kernel, ignoring if a sibling socket has any OS-thread waiting to accept
. So while having a single listening socket you may experience contention in the accept queue, having multiple listening sockets you may see disparity in the latency because one OS-thread has more load. (It's explained in detail in this cloudflare blog entry)