[erlang-questions] TCP receive buffer: erlang size VS kernel size

Vincent de Phily vincent.dephily@REDACTED
Thu Aug 25 15:08:01 CEST 2011


Hi list,

while playing with the TCP receive buffer size, I noticed two strange things :


1) The size seen in inet:getopts(S, [recbuf]) is the double of the size set
   via gen_tcp:listen/2 (with some min/max values).

* I assume that the discrepancy is between an in-VM buffer and the in-kernel
  buffer ?
* Why is that 2x ratio necessary ?
* The docs never mention that there are two different buffers, and which
  function reads/writes which buffer size. I only expected the kernel buffer,
  and I definitely expected 'recbuf' to represent the same object for
  inet:getopt as for gen_tcp:listen.


2) If I don't specify a recbuf in gen_tcp:listen/2, the kernel buffer (as seen
   in inet:getopts) is 87 KB while the VM buffer (as seen in the size of
   received packets) is 1460 B.

* That's a much bigger difference ratio than previously seen.
* The default value of 1460 bytes sounds too small for anything but the most
  ressource-constrained devices (my kernel agrees, but I admit having 4GB of
  memory).


This is on linux 3.0.3, erlang R13B04 and R14B03.
Here's a script for experimentation (using "nc -q1 $HOST $PORT < bigfile" on 
the client side):

#!/usr/bin/env escript

-mode(compile).

main([Port, Active, Size, Timeout, Sleep, Buffer]) ->
    main(list_to_integer(Port),
         list_to_atom(Active),
         list_to_integer(Size),
         list_to_integer(Timeout),
         list_to_integer(Sleep),
         list_to_integer(Buffer)).

main(Port, Active, Size, Timeout, Sleep, Buffer) ->
    {ok, Listen} = gen_tcp:listen(Port, [binary,
                                         {reuseaddr, true},
                                         {active, Active}] ++ case Buffer > 0 
of true -> [{recbuf, Buffer}]; false -> [] end),
    accept(Listen, Port, Active, Size, Timeout, Sleep).

accept(Listen, Port, Active, Size, Timeout, Sleep) ->
    io:format("accepting connections on ~p~n", [Port]),
    {ok, Socket} = gen_tcp:accept(Listen),
    io:format("~w ~w~n", 
[element(1,lists:unzip(element(2,inet:getstat(Socket)))), 
element(2,inet:getopts(Socket, [recbuf]))]),
    loop(Socket, Active, Size, Timeout, Sleep),
    accept(Listen, Port, Active, Size, Timeout, Sleep).

loop(Socket, Active, Size, Timeout, Sleep) ->
    io:format("~w\t", [stat(Socket)]),
    receive
        {tcp, Socket, Data1} ->
            case Active of
                true ->
                    io:format("case1 ~p~n",[byte_size(Data1)]);
                once ->
                    Sleep > 0 andalso timer:sleep(Sleep),
                    case gen_tcp:recv(Socket, Size, Timeout) of
                        {ok, Data2} ->
                            io:format("case2 ~p ~p~n", [byte_size(Data1), 
byte_size(Data2)]);
                        Other ->
                            io:format("case3 ~p ~p~n", [byte_size(Data1), 
Other])
                    end,
                    inet:setopts(Socket, [{active, once}])
            end,
            loop(Socket, Active, Size, Timeout, Sleep);
        Other ->
            io:format("~p~n",[Other]),
            gen_tcp:close(Socket)
    after 1000 ->
            io:format("timeout~n",[]),
            gen_tcp:close(Socket)
    end.

stat(Socket) ->
    case inet:getstat(Socket) of
        {ok, S} -> element(2,lists:unzip(S));
        Other -> Other
    end.

-- 
Vincent de Phily



More information about the erlang-questions mailing list