[erlang-questions] [Q] prim_inet:async_accept and gen_tcp:send

Serge Aleynikov <>
Fri Jul 13 05:19:20 CEST 2007


You may also want to copy some socket options on the accepted socket the 
same way it's done in prim_inet.  Here's a more complete extract 
(slightly trimmed) from a non-blocking TCP gen_server extracted from one 
of working projects.  A couple of points to note are:

1. Initially the listening socket is set to passive mode, so that the 
accepted socket wouldn't attempt to send messages to the listener's 
gen_server process.  As soon as the ownership is switched to the 
Module's handler Pid, it's safe to switch it to the {accept, once} mode 
in that module.

2. I am not a 100% sure if it's a good idea to retry accept attempts in 
case when acceptor returns an error {inet_async, ListSock, Ref, Error}. 
  So we might as well crash the listener and let supervisor handle 
listener's restart.


init(Port, Module) ->
     process_flag(trap_exit, true),

     %% The socket options will be set on the acceptor socket automatically
     case gen_tcp:listen(Port,[binary, {packet, 2}, {reuseaddr, true},
                               {keepalive, true}, {backlog, 128},
                               {active, false}])
     of
     {ok, Listen_socket} ->
         %%Create first accepting process
         {ok, Ref} = prim_inet:async_accept(Listen_socket, -1),
         {ok, #state{listener        = Listen_socket,
                     acceptor        = Ref,
                     module          = Module}};
     {error, Reason} ->
         {stop, Reason}
     end.

handle_info({inet_async, ListSock, Ref, {ok, CliSocket}}, 
#state{listener=ListSock, acceptor=Ref, module=M} = State) ->
     case set_sockopt(ListSock, CliSocket) of
     ok ->
         %% New client connected
         {ok, Pid} = erlang:apply(Module, start_link, [CliSocket]),
         gen_tcp:controlling_process(CliSocket, Pid),
         %% Instruct the new FSM that it owns the socket.
         gen_fsm:send_event(Pid, socket_ready),
         {ok, NewRef} = prim_inet:async_accept(ListSock, -1),
         {noreply, State#state{acceptor=NewRef}};
     {error, Reason} ->
         error_logger:error_msg("Error setting socket options: ~p.\n", 
[Reason]),
         {stop, Reason, State}
     end;

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


set_sockopt(ListSock, CliSocket) ->
     true = inet_db:register_socket(CliSocket, inet_tcp),
     case prim_inet:getopts(ListSock, [active, nodelay, keepalive, 
delay_send, priority, tos]) of
	{ok, Opts} ->
	    case prim_inet:setopts(CliSocket, Opts) of
		ok    -> ok;
		Error -> gen_tcp:close(CliSocket), Error
	    end;
	Error ->
	    gen_tcp:close(CliSocket), Error
     end.


Tony Rogvall wrote:
> Reading the code for accept in the module inet_tcp.erl (in lib/kernel)
> accept makes a call to inet_db:register_socket(S, ?MODULE).
> 
> you need to call it with ?MODULE replaced by the atom inet_tcp.
> 
> /Tony
> 
> 
> On 12 jul 2007, at 16.51, Ladislav Lenart wrote:
> 
>> Hello,
>>
>> based on a previous thread about prim_inet:async_accept we tried to
>> use it ourselves but the connection socket we get is unusable. To
>> repeat do following in the erlang shell:
>>
>> $> {ok, Port} = gen_tcp:listen(6667, [list, {packet, line},  
>> {active, false}]).
>> {ok, #Port<0.70890>}
>> $> {ok, Ref} = prim_inet:async_accept(P, -1).
>> {ok, 0}
>>
>> Now telnet to localhost:6667 and continue:
>>
>> $> receive {inet_async, Port, Ref, {ok, Socket}} -> {ok, Socket} end.
>> {ok, #Port<0.70891>}
>>
>> However evaluating gen_tcp:send(Socket, Data) crashes with
>> {undef, [{undefined, send, [Socket, Data]}, ...]}
>>
>> We found out that problem is in gen_tcp:send/2 which
>> in turn calls inet_db:lookup_socket(Socket) which calls
>> erlang:port_get_data(Socket) which returns undefined
>> (instead of inet_tcp?).
>>
>> Any clues to what we are doing wrong?
>>
>> Thanks,
>>
>> Ladislav Lenart
>>
>> _______________________________________________
>> 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