Hatena::Grouperlang

Erlang Mind

 | 

2009-01-03

2009 年は TCP のお勉強から。

| 23:13

結論 ... TCP は難しい。

やりたいことはプロセスプールを作っておいてそれぞれが gen_tcp:accept 状態にしておく。

これは R11B-3 から一つの待ち受けソケットに対して複数の Erlang プロセスから gen_tcp:accept が呼び出すことが出来るようになったから。

そして、 accept して出来た新しいソケットを別プロセスに渡してもう一度 accept 状態にする。

ということがやりたいのだけれど、どーもうまくいかない、書き方間違ってるんだろうなぁ。

ちなみに accept 後に使うプロセスは使い捨て。accept に使うプロセスはすーぱーばいざーにでも面倒を見させておくのが理想型。

Erlang 的な TCP サーバの回答は個人的にこれだと思うんだけどなぁ。最初に起動しておくプロセスは自由に設定できると幸せに慣れそう。

まだまだ初心者のレベルにも到達してないな。

あ、ちなみに動きません。Accept するところまでは行くんですが送受信が上手いこと言ってません。

-module(tcp_echo_server).
-compile(export_all).

-define(MAX_ACCEPTOR, 5).

start_link() ->
  spawn(fun() -> init() end).

init() ->
  case gen_tcp:listen(
    5000, [{active, true}, binary, {packet, line}, {reuseaddr, true}]
  ) of
    {ok, ListenSocket} ->
      loop(ListenSocket);
    {error, _Reason} ->
      error
  end,
  receive
    {ok} ->
      ok
  end.

stop() ->
  ok.

loop(ListenSocket) ->
  loop(ListenSocket, 0).
loop(_ListenSocket, ?MAX_ACCEPTOR) ->
  ok;
loop(ListenSocket, Count) ->
  Pid = spawn(fun() -> accept(ListenSocket) end),
  io:format("loop: ~p, ~p\n", [Count, Pid]),
  loop(ListenSocket, Count + 1).

accept(ListenSocket) ->
  case gen_tcp:accept(ListenSocket) of
    {ok, Socket} ->
      io:format("accept: ~p\n", [self()]),
      spawn(fun() -> connect(Socket) end),
      accept(ListenSocket);
    {error, _Reason} ->
      accept(ListenSocket)
  end.

connect(Socket) ->
  receive
    {tcp, Socket, Packet} ->
      io:format("~p\n", [Packet]),
      case gen_tcp:send(Socket, [Packet]) of
        ok ->
          connect(Socket);
        {error, _Reason} ->
          io:format("error: ~p\n", [self()]),
          ok = gen_tcp:close(Socket)
      end;
    {tcp_closed, Socket} ->
      io:format("tcp_closed: ~p\n", [self()]),
      ok = gen_tcp:close(Socket);
    {tcp_error, Socket, _Reason} ->
      io:format("tcp_error: ~p\n", [self()]),
      ok = gen_tcp:close(Socket)
  end.

追記

  • 力武さんからのつっこみにより、{active, true} にしてみた。最終的には {active, once} に成るのだろうが、今は簡単なエコーサーバなので {active, true} でよし。
  • join で無理矢理待たせていたのを receive で待たせました。

jj1bdxjj1bdx2009/01/03 23:36CPU使用率が100%(=コア1つ分)にすぐ行ってしまうのは,join()で回ってるからなんでしょうか.ここは別の方法で待たせたほうがいいかも.

jj1bdxjj1bdx2009/01/03 23:45{active, false} のときは gen_tcp:recv/2 あるいは gen_tcp:recv/3 を使えとありますね.
http://www.erlang.org/doc/man/gen_tcp.html
acceptの項の最後を参照

VoluntasVoluntas2009/01/04 03:18join() は wait かけるための最低の手です ... orz ここも見直してみます。
{active, true} のときは recv ... 未熟でした。もう一度そこを読んでみます。

jj1bdxjj1bdx2009/01/04 08:37client:client/1 の gen_tcp:connect/3の3番目の引数には ? が必要ですね(マクロだから).

VoluntasVoluntas2009/01/04 16:42おぉ、抜けてました。ご指摘ありがとうございます。修正しておきました:-)

CassaraCassara2012/10/08 20:54Holy Toledo, so glad I clckied on this site first!

bkmordobkmordo2012/10/09 05:574tZvuJ <a href="http://zehjwmjpcoki.com/">zehjwmjpcoki</a>

yyycuvdnzyyycuvdnz2012/10/10 07:58xCiddm , [url=http://gzmhquslkjha.com/]gzmhquslkjha[/url], [link=http://nmaogmzlhulx.com/]nmaogmzlhulx[/link], http://mqlpicqhechk.com/

drdnderdrdnder2012/10/11 14:08c9XYnu <a href="http://juegccmxktvp.com/">juegccmxktvp</a>

rfncomxvjrfncomxvj2012/10/12 03:31UsbXzD , [url=http://dqgeiymejisp.com/]dqgeiymejisp[/url], [link=http://ihahrqezdfnx.com/]ihahrqezdfnx[/link], http://ckvytfbhohkb.com/

 |