6

使用 {packet,4} 通过 localhost 的两个不同端口传输 1G 数据仅需 8 秒,而使用 {packet,raw} 无法在 30 秒内完成相同的任务。我知道如果使用后一种方法,数据将以数万小块的形式到达(在archlinux上大小为1460字节)。我已经了解了 TCP/IP 协议的某些方面,并且几天来一直在思考这个问题,但仍然无法弄清楚确切的区别是什么。真诚期待一些自下而上的解释。

-module(test).

-export([main/1]).

-define(SOCKOPT, [binary,{active,true},{packet,4}]).

main(_) ->
    {ok, LSock} = gen_tcp:listen(6677, ?SOCKOPT),
    spawn(fun() -> send() end),
    recv(LSock).

recv(LSock) ->
    {ok, Sock} = gen_tcp:accept(LSock),
    inet:setopts(Sock, ?SOCKOPT),
    loop(Sock).

loop(Sock) ->
    receive
        {tcp, Sock, Data} ->
            io:fwrite("~p~n",[bit_size(Data)]),
            loop(Sock);
        {tcp_closed, Sock} -> ok
    end.

send() ->
    timer:sleep(500),
    {ok, Sock}=gen_tcp:connect("localhost", 6677, ?SOCKOPT),
    gen_tcp:send(Sock, binary:copy(<<"1">>, 1073741824)),
    gen_tcp:close(Sock).

$ time escript test.erl
8589934592
real 0m8.919s user 0m6.643s sys 0m2.257s

4

3 回答 3

1

当数据被小块接收时,接收端的内核缓冲区会很快填满。它将减少发送方的拥塞窗口大小,迫使发送方以较低的速率推送数据。

于 2014-05-25T10:55:39.490 回答
1

当您使用 {packet,4} 时,erlang 首先读取 4 个字节以获取数据长度,分配一个缓冲区来保存它,并在获取每个 tcp 数据包后将数据读入缓冲区。然后它将缓冲区作为一个数据包发送到您的进程。这一切都发生在内置的读取代码中,这相当快。

当您使用 {packet,raw} 时,erlang 在接收到每个 tcp 数据包后会向您的进程发送一条消息,因此对于每个 tcp 数据包它会做更多的事情。

于 2012-12-16T18:04:58.990 回答
-1

尝试

-define(SOCKOPT, [binary,{active,true},{recbuf, 16#FFFFFF}, {sndbuf, 16#1FFFFFF}])
于 2019-11-07T09:31:33.923 回答