1

次のコードは{packet,0}、関数呼び出しのオプションでは機能しgen_tcp:connect()ますが、1、2、および4では機能しません(ただし、4でのみテストし、1と2も機能しないと想定しています)。私が持っている質問は、なぜそうではないのか、そして一方を他方の上に使用することが重要なのかということです。基本的に、Erlangのドキュメントはパケットオプションに関する主題の詳細な説明を扱っておらず、JoeArmstrongによるProgrammingErlangも詳細を提供していません。彼は、UDPとは異なり、tcpパケットは送信時に受信されると常に思っていましたが、パケットは順番に再構成されないと説明しています。私が持っている興味深いメモの1つは、このページのクライアントサーバーにオプションがあり{packet,4}、正常に動作し、以下のこのコードと非常によく似ていることです。これがサーバーシェルの出力です{packet,4}以下のコードで使用されるオプション。

Erlang R16A (erts-5.10) [smp:8:8] [async-threads:10]

Eshell V5.10  (abort with ^G)
1> cd("c:/erlang").
c:/erlang
ok
2> c(cp3).
{ok,cp3}
3> cp3:server().
Started Server:
<0.41.0>
Accept Server:
Pid <0.43.0>
Connection accepted 
Accept Server:
Loop Server:
Error on socket #Port<0.2256> reason: einval

これはクライアント側のシェル出力です。

Erlang R16A (erts-5.10) [smp:8:8] [async-threads:10]

Eshell V5.10  (abort with ^G)
1> cd("c:/erlang").
c:/erlang
ok
2> cp3:client().
exit
3> 

これは使用されるコードです、

-module(cp3).
-export([client/0, server/0,start/0,accept/1,enter_loop/1,loop/1]).

client() ->
    {ok, Socket} =  gen_tcp:connect("localhost", 4001,[binary, {packet, 4}]),
    ok = gen_tcp:send(Socket, "packet"),
    receive
        {tcp,Socket,String} ->
            io:format("Client received = ~p~n",[String]),       
            io:format("Client result = ~p~n",[String]),
            gen_tcp:close(Socket)
        after 1000 ->
            exit        
    end.

server() -> 
    Pid = spawn(fun()-> start() end),
    Pid.

start() ->  
    io:format("Started Server:~n"),
    {ok, Socket} = gen_tcp:listen(4001, [binary, {packet, 4},{reuseaddr, true},{active, false}]),
    accept(Socket).

accept(ListenSocket) ->
    io:format("Accept Server:~n"),
    case gen_tcp:accept(ListenSocket) of
        {ok, Socket} ->
            Pid = spawn(fun() ->
                io:format("Connection accepted ~n", []),
                enter_loop(Socket)
            end),
            io:format("Pid ~p~n",[Pid]),
            gen_tcp:controlling_process(Socket, Pid),
            Pid ! ack,
            accept(ListenSocket);
        Error ->
            exit(Error)
    end.

enter_loop(Socket) ->
    %% make sure to acknowledge owner rights transmission finished
    receive ack -> ok end,
    loop(Socket).

loop(Socket) ->   
    io:format("Loop Server:~n"),
    case gen_tcp:recv(Socket, 6) of
    {ok, Data} ->  
        case Data of
            <<"packet">> ->                 
                io:format("Server replying = ~p~n",[Data]),   
                gen_tcp:send(Socket, Data),
                loop(Socket)                  
        end;
    {error, Reason} ->      
        io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])          
    end.
4

1 に答える 1

1

コードはほぼ問題ありません。ループ(ソケット)の行を変更するだけです。

ケースgen_tcp:recv(Socket、6)of

ケースgen_tcp:recv(Socket、0)of

ドキュメントを参照してください:

recv(ソケット、長さ)-> {ok、パケット} | {エラー、理由} recv(Socket、Length、Timeout)-> {ok、Packet} | {エラー、理由}

タイプ:Socket = socket()Length = integer()> = 0 Timeout = timeout()Packet = string()| binary()| HttpPacketReason=クローズ| inet:posix()HttpPacket = term()erlang:decode_packet/3のHttpPacketの説明を参照してください。

この関数は、パッシブモードでソケットからパケットを受信します。閉じたソケットは、戻り値{error、closed}で示されます。

Length引数は、ソケットがrawモードの場合にのみ意味があり、読み取るバイト数を示します。長さ=0の場合、 使用可能なすべてのバイトが返されます。長さ>0の場合、正確に長さのバイトが返されるか、エラーが返されます。ソケットが反対側から閉じられたときに、長さバイト未満のデータを破棄する可能性があります。

オプションのTimeoutパラメーターは、タイムアウトをミリ秒単位で指定します。デフォルト値は無限大です。

この変更で機能しますが、クライアントが各呼び出しの後にソケットを閉じているため、エラーメッセージが表示されます。クライアントからソケットを閉じることが役立つかどうかはわかりません。次のようにクライアントを変更することで、この動作を変更できます。

client() ->
    {ok, Socket} =  gen_tcp:connect("localhost", 4001,[binary, {packet, 4}]),
    ok = gen_tcp:send(Socket, "packet"),
    receive
        {tcp,Socket,String} ->
            io:format("Client received = ~p~n",[String]),       
            io:format("Client result = ~p~n",[String])
            %gen_tcp:close(Socket)
        after 1000 ->
            exit        
    end.
于 2013-03-26T07:39:18.993 に答える