[erlang-questions] Erlang OTP design principle

Serge Aleynikov <>
Tue Jul 10 13:56:25 CEST 2007


There's a prim_inet:async_accept/2 function that does what you need:

{ok, Ref} = prim_inet:async_accept(Listen_socket, -1),

Here's a snippet from a non-blocking tcp gen_server that exploits this 
feature:

init(Port, Module) ->
     process_flag(trap_exit, true),
     case gen_tcp:listen(Port, ?LISTEN_SOCK_OPTIONS) of
     {ok, Listen_socket} ->
         %%Create first accepting process
         {ok, Ref} = prim_inet:async_accept(Listen_socket, -1),
         {ok, #state{module=Module, listener=Listen_socket,
                     acceptor=Ref}};
     {error, Reason} ->
         {stop, Reason}
     end.

handle_info({inet_async, ListSock, Ref, {ok, CliSocket}}, 
#state{module=Module, listener=ListSock, acceptor=Ref} = State) ->
     %% New client connected
     {ok, Pid} = erlang:apply(Module, start_link, [CliSocket]),
     gen_tcp:controlling_process(CliSocket, Pid),
     %% Instruct the new TCP server that it owns the socket
     Pid ! socket_ready,
     {ok, NewRef} = prim_inet:async_accept(ListSock, -1),
     {noreply, State#state{acceptor=NewRef}};

handle_info({inet_async, ListSock, Ref, Error}, 
#state{listener=ListSock, acceptor=Ref} = State) ->
     error_logger:error_msg("Error in socket acceptor: ~p. 
Retrying.\n", [Error]),
     {stop, {acceptor, Error}};



Eranga Udesh wrote:
> Using {active, once} or {active, true} instead of gen_tcp:recv, I can use a
> gen_server or my own OTP compliant process to receive TCP messages.
> 
> But what about gen_tcp:accept? Since this is a blocking function, if I try
> to do a code load, the Acceptor Thread gets killed? Is there anyway that I
> can write this better?
> 
> BRgds,
> - Eranga
> 
> 
> 
> 
> -----Original Message-----
> From: Ulf Wiger (TN/EAB) [mailto:] 
> Sent: Monday, June 11, 2007 2:48 PM
> To: Eranga Udesh; 
> Subject: RE: [erlang-questions] Erlang OTP design principle
> 
> 
> If you want to be able to handle messages while
> waiting for a TCP message, you may want to use
> inet:setopts(Sock, [{active, once}]), and then
> wait for the packet in a normal receive clause.
> 
> If the waiting is done in e.g. a gen_server, you
> get the handling of system messages for free.
> Otherwise, you need to read the OTP Design Principles
> document, 
> 
> http://www.erlang.org/doc/doc-5.5.4/doc/design_principles/part_frame.htm
> l
> 
> chapter 6.2 "Special Processes", on how to handle
> system messages on your own.
> 
> (or use something like plain_fsm in Jungerl, if 
> you really want to write textbook receive clauses.)
> 
> BR,
> Ulf W
> 
>> -----Original Message-----
>> From:  
>> [mailto:] On Behalf Of Eranga Udesh
>> Sent: den 11 juni 2007 07:08
>> To: 
>> Subject: [erlang-questions] Erlang OTP design principle
>>
>> Hi,
>>
>> What's the best way to make do_recv/2 function below, OTP 
>> compliant? I.e. it should receive messages from other 
>> processes, handle code update requests, terminate, etc.
>>
>> Why gen_tcp, gen_udp, etc., are written as behaviors like 
>> gen_server, so that in a handle_*, it will receive incoming 
>> messages, etc?
>>
>> Thanks,
>> - Eranga
>>
>>
>>
>>
>> server() ->
>>     {ok, LSock} = gen_tcp:listen(5678, [binary, {packet, 0}, 
>>                                         {active, false}]),
>>     {ok, Sock} = gen_tcp:accept(LSock),
>>     {ok, Bin} = do_recv(Sock, []),
>>     ok = gen_tcp:close(Sock),
>>     Bin.
>>
>> do_recv(Sock, Bs) ->
>>     case gen_tcp:recv(Sock, 0) of
>>         {ok, B} ->
>>             do_recv(Sock, [Bs, B]);
>>         {error, closed} ->
>>             {ok, list_to_binary(Bs)}
>>     end.
>>
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> 
>> http://www.erlang.org/mailman/listinfo/erlang-questions
>>
> 
> _______________________________________________
> erlang-questions mailing list
> 
> http://www.erlang.org/mailman/listinfo/erlang-questions
> 




More information about the erlang-questions mailing list