[erlang-questions] gen_tcp:recv and hairloss

Kevin q2h46uw02@REDACTED
Sat Nov 8 05:20:21 CET 2008


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?!?

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.
   










More information about the erlang-questions mailing list