[erlang-questions] gen_tcp:recv and hairloss

Pablo Polvorin <>
Sat Nov 8 16:38:11 CET 2008


Hi,

2008/11/8 Kevin <>:
>
> I'm having a hell of a time with gen_tcp:recv
>
> here are the options I use for gen_tcp:listen
>
> -define(TCP_OPTS, [binary, {packet, raw}, {active, false},  {reuseaddr,
> true}]).
>
> So the idea is all the listening and accept stuff is handled
> successfully at the top of a gen_server.
>
> Here's a simplified idea at the gen_server level, (there's some
> conditional handling that gets confusing so I took it out)
>
> loop(Sock, Fsm) ->
>
>    case gen_tcp:recv(Sock, 0, ?RECV_TIMEOUT) of
>    {ok, Request} ->
>         ok = gen_fsm:send_event(Fsm, {Request, Sock}),
>         loop(Sock, Fsm)
>    {error, Reason} ->
>           dont_worry_bout_it
>    end.
>
> There might be a typo from the editing for this email, but this, so far,
> has worked great.
>
> Now in the Fsm, I examine the Request binary, have some fun with it,
> then use gen_tcp:send(Sock, Msg)
> to reply.  This all works great, and I've hammered it and it takes a
> good load.
>
> So to recap, the gen server loops over the input, usually telnet for
> ....ing purposes, and passes each line
> to the Fsm, which then replies.
>
> I decided I wanted a tighter loop inside the Fsm, so I reproduced the
> same loop there, given the same socket,
> and I get the error "ealready", which means something like "operation
> already in progress".
>
> Basically I can't read from the socket unless I come back up out of the
> Fsm and let the same loop get the next line.  What is so
> special about the gen_server process that can *read* from the socket and
> the fsm process that cant?!?
>

there is nothing special about gen_server.
I think your problem is that you are trying to perform two gen_tcp:recv/2
operations on the same socket in parallel.

> I tried to reproduce the problem, and I'm having NO problem.  One
> difference I can think of is that the recv in the Fsm is in a different
> process.
> Here is a simplified version that shows no problems.  Its an echo server
> that goes quiet when you tell it "sssh" in telnet.
>
> start() ->
>    {ok, LSock} = gen_tcp:listen(5678, [binary, {packet, raw},
>                                        {active, false},
>                                        {reuseaddr, true}]),
>    {ok, Sock} = gen_tcp:accept(LSock),
>    do_recv(Sock),
>    gen_tcp:close(Sock).
>
>
> do_recv(Sock) ->
>    case gen_tcp:recv(Sock, 0) of
>        {ok, B} ->
>            case B of
>                <<"sssh\r\n">> -> %% silent mode
>                    sssh(Sock);
>                X ->
>                    gen_tcp:send(Sock, X),
>                    do_recv(Sock)
>            end;
>        {error, Reason} ->
>            io:format("Error:~p~n", [Reason])
>    end.
>
>
> sssh(Sock) ->
>    case gen_tcp:recv(Sock, 0) of
>        {ok, _} ->
>            sssh(Sock);
>        {error, Reason} ->
>            io:format("Error2:~p~n", [Reason])
>    end.
>
>

Test this and see what happens:

test() ->
   {ok,LS} = gen_tcp:listen(7000,[binary,{active,false}]),
   {ok,Sock} = gen_tcp:accept(LS),
   spawn(fun() ->  do_recv(Sock) end),
   spawn(fun() ->  do_recv(Sock) end),
   ok.


do_recv(Socket) ->
   io:format("Recv: ~p~n", [ gen_tcp:recv(Socket,0)]).



More information about the erlang-questions mailing list