[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