6

{packet,4} を使用して localhost の 2 つの異なるポートを介して 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 パケットを取得した後にデータをバッファーに読み取ります。次に、バッファを 1 つのパケットとしてプロセスに送信します。これはすべて組み込みの読み取りコード内で行われるため、かなり高速です。

{packet,raw} を使用すると、erlang はデータの各 tcp パケットを受信した後にプロセスにメッセージを送信するため、各 tcp パケットに対してさらに多くのことを行います。

于 2012-12-16T18:04:58.990 に答える