Curious behaviour of gen_tcp

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Curious behaviour of gen_tcp

Alexis Le-Quoc
Hello everyone,

I'm using the following program structure to have an erlang process
communicate with a socket based server (written in perl). The code is
simplified on purpose.

start() ->
  loop_idle().

loop_idle(Queue)
  case not_empty(Queue) of
    true ->
      send_and_loop(Queue);
    _ ->
      do_nothing
  end;

  receive
    {send, Data} ->
      send_and_loop(Data);
    _ ->
      log_crap
  end.

send_and_loop(Queue) ->
  {ok, Socket} = gen_tcp:connect("localhost", 1, [binary, {packet, 0}]),
  gen_tcp:send(Socket, Queue:pop()),
  loop_busy(Queue, Socket, <<>>).

loop_busy(Queue, Socket, Buffer) ->
  receive
    {tcp, Socket, Data} ->
      loop_busy(Socket, concat_binary([Buffer, Data]);
    {tcp_closed, Socket} ->
      io:fwrite("Finished ~w", [length(binary_to_list(Buffer)]),
      loop_idle(Queue);
    Any ->
      io:fwrite("Received ~w~n", [Any])
  end.

%%%%%%%%%%%%%

This works great except that for responses bigger than 70 KB, I don't get
consistent results, i.e. sometimes, the response received by erlang is
about the right size (compared to what was sent by the server, always the
same size), sometimes, it's half or a quarter of the size.

Am I correct in assuming that the {tcp_closed..} pattern does not
necessarily match after {tcp, Socket, Data}? I.e. the process will match
some {tcp, Socket, Data} and then, if {tcp_closed...} has been received,
it *can* match it and exit the loop *while* there are still {tcp, Socket,
Data} messages in its mailbox.

If this is correct, does it mean that I need to spawn a listener process
which will do gen_tcp:recv() and notify the parent that it has received
all data?

I have to say I'm a bit boggled by this one.

Alexis



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Curious behaviour of gen_tcp

tobbe

When doing pattern matching in a receive clause,
Erlang takes the first message in the queue and
tries to match it agains any of the receive clauses
(in top-down order). See attached example.

However, if this can happend in your gen_tcp case I don't know.

Cheers /Tobbe
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-module(aa).
-export([bb/0]).

%%%
%%% See how messages are received:
%%%
%%% 1> P=aa:bb().
%%% <0.28.0>
%%% 2> P! tcp.
%%% tcp
%%% 3> P! tcp.
%%% tcp
%%% 4> P! tcp_closed.
%%% tcp_closed
%%% 5> P! tcp.      
%%% tcp
%%% 6> P! tcp.
%%% tcp
%%% 7> P! start.
%%% start
%%% got tcp
%%% got tcp
%%% got tcp_closed
%%% got tcp
%%% got tcp
%%% 8>
%%%

bb() -> spawn(fun() -> init() end).

init() ->
    receive start -> true end,
    loop().

loop() ->
    receive
        tcp ->
            io:format("got tcp~n"),
            loop();

        tcp_closed ->
            io:format("got tcp_closed~n"),
            loop()
    end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


Loading...