[erlang-questions] gen_tcp:recv and hairloss
Pablo Polvorin
ppolv@REDACTED
Sat Nov 8 16:29:14 CET 2008
Hi,
2008/11/8 Kevin <q2h46uw02@REDACTED>:
>
> 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 operation 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