2012年2月25日土曜日

Erlang gen_tcp:connect { active, false } オプション

tcpの勉強をしている。
Cのプログラムを組んで、Erlangでも試してみることをしている。

そこで、Erlangのオンラインマニュアルにあるサンプルを動かしてみた。
Erlang -- gen_tcp : http://www.erlang.org/doc/man/gen_tcp.html

connect() のオプション{ active, false }について、試したことを書き記しておく。

{ active, false }の有無で、データ受信の方法が変わる。
以下にまとめたものを示す。
受信の対応を間違えると落ちます。crash_dump吐きます。
以下にソースを記す。
コメントアウトしているところが、{ active, false }ありのバージョン。

◆クライアント

-module(sample_client).
-compile(export_all).

client() ->
    SomeHostInNet = "localhost",
    { ok, Sock } = gen_tcp:connect( SomeHostInNet, 5678,
                                    [ binary, { packet, 0 } ] ),
    ok = gen_tcp:send( Sock, "Some Data" ),
    ok = gen_tcp:close( Sock ).

◆サーバ

-module(sample_server).
-compile(export_all).

server() ->
    %{ ok, LSock } = gen_tcp:listen( 5678,
     %                               [ binary, { packet, 0 }, { active, false } ] ),
    { ok, LSock } = gen_tcp:listen( 5678,
                                    [ binary, { packet, 0 } ] ),
    { ok, Sock } = gen_tcp:accept( LSock ),
    { ok, Bin } = do_recv( Sock, [] ),
    ok = gen_tcp:close( Sock ),
    io:format( "~p~n", [ Bin ] ).

%do_recv( Sock, Bs ) ->
%    case gen_tcp:recv( Sock, 0 ) of
%        { ok, B } ->
%            do_recv( Sock, [ Bs, B ] );
%        { error, closed } ->
%            { ok, list_to_binary( Bs ) }
%    end.
do_recv( Sock, Bs ) ->
    receive
        { tcp, Sock, B } ->
            do_recv( Sock, [ Bs, B ] );
        { tcp_closed, Sock } ->
            { ok, list_to_binary( Bs ) };
        { tcp_error, Sock, Reason } ->
            io:format( "recv error:~p~n", [ Reason ] ),
            { error, Sock, Reason }
    end.

動かし方
サーバを動かした後、クライアントを動かす。
◆コンパイル
$> erlc sample_server.erl
$> erlc sample_client.erl

◆起動
サーバとクライアントは別端末でやる
$> erl -noshell -run sample_server server -run init stop
<<"Some Data">>
(他端末で)
$> erl -noshell -run sample_client client -run init stop