[erlang-questions] [Q] prim_inet:async_accept and gen_tcp:send
Serge Aleynikov
saleyn@REDACTED
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
>> erlang-questions@REDACTED
>> http://www.erlang.org/mailman/listinfo/erlang-questions
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions
>
More information about the erlang-questions
mailing list