読者です 読者をやめる 読者になる 読者になる

gen_sctp のサンプル試してみた

erlang sctp

皆さんすでに試してるとは思いますが、一応まとめてみました。
SCTP をよく理解していないので、間違っている可能性大

環境

ubuntu
Ubuntu 9.10 a5 server 64bit
apt-get
erlang-base-hipe erlang-eunit erlang-dev
server ip
192.168.0.24

作業

サーバ

v@ubuntu:~/work/sctp$ erlc sctp_server.erl 
v@ubuntu:~/work/sctp$ erl
Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1> sctp_server:server().
Listening on any:2009. #Port<0.397>
Received: {ok,{{127,0,0,1},53413,[],{sctp_assoc_change,comm_up,0,10,5,2}}} 
Received: {ok,{{127,0,0,1},
               53413,
               [{sctp_sndrcvinfo,0,0,[],0,0,0,4177896368,0,2}],
               <<"Test 0">>}}
Received: {ok,{{127,0,0,1},
               53413,[],
               {sctp_paddr_change,{{192,168,0,24},53413},addr_confirmed,2,2}}}
Received: {ok,{{127,0,0,1},53413,[],{sctp_assoc_change,comm_lost,3072,0,0,2}}}

クライアント

v@ubuntu:~/work/sctp$ erlc sctp_client.erl 
v@ubuntu:~/work/sctp$ erl
Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1> sctp_client:client().
Connection Successful, Assoc={sctp_assoc_change,comm_up,0,5,10,1}
ok
{error,einval}
ok
ok

一個だけ失敗してますね。これは失敗する例なので問題ないはずです。

追記

なぜ失敗しているかというと、宣言しているストリーム番号を越えたストリームを使おうとしているからです。#sctp_initmsg{num_ostreams=5} でストリームの数は 5 本です。つまり 0 - 4 という番号がついているにもかかわらず、5 番目のストリームを使おうとして失敗しているのです。これを回避するには #sctp_initmsg{num_ostreams=6} と宣言すれば使えるようになります。

そーす

gen_sctp のドキュメントそのままなんですが、そのままだと動きません。

修正前

{ok,S} = gen_sctp:open([{ip,IP},{port,Port}],[{recbuf,65536}]),

修正後

{ok,S} = gen_sctp:open([{ip,IP},{port,Port},{recbuf,65536}]),

すべての引数を Options にしてしまいましょう。
あとポート番号を 2006 から 2009 に変更してあります。

あと、これリストで渡すとループする気が。。。

server([Host,Port]) when is_list(Host), is_list(Port) ->
  {ok, #hostent{h_addr_list = [IP|_]}} = inet:gethostbyname(Host),
  io:format("~w -> ~w~n", [Host, IP]),
  % 修正前
  % server([IP, list_to_integer(Port)]).
  % 修正後
  server(IP, list_to_integer(Port)).

sctp_server

-module(sctp_server).

-export([server/0,server/1,server/2]).

-include_lib("kernel/include/inet.hrl").
-include_lib("kernel/include/inet_sctp.hrl").

server() ->
  server(any, 2009).

server([Host,Port]) when is_list(Host), is_list(Port) ->
  {ok, #hostent{h_addr_list = [IP|_]}} = inet:gethostbyname(Host),
  io:format("~w -> ~w~n", [Host, IP]),
  server(IP, list_to_integer(Port)).

server(IP, Port) when is_tuple(IP) orelse IP == any orelse IP == loopback,
                      is_integer(Port) ->
  {ok,S} = gen_sctp:open([{ip,IP},{port,Port},{recbuf,65536}]),
  io:format("Listening on ~w:~w. ~w~n", [IP,Port,S]),
  ok = gen_sctp:listen(S, true),
  server_loop(S).

server_loop(S) ->
  case gen_sctp:recv(S) of
  {error, Error} ->
    io:format("SCTP RECV ERROR: ~p~n", [Error]);
  Data ->
    io:format("Received: ~p~n", [Data])
  end,
  server_loop(S). 

sctp_client.erl

-module(sctp_client).

-export([client/0, client/1, client/2]).
-include_lib("kernel/include/inet.hrl").
-include_lib("kernel/include/inet_sctp.hrl").

client() ->
  client([localhost]).

client([Host]) ->
  client(Host, 2009);

client([Host, Port]) when is_list(Host), is_list(Port) ->
  client(Host,list_to_integer(Port)),
  init:stop().

client(Host, Port) when is_integer(Port) ->
  {ok,S} = gen_sctp:open(),
  {ok,Assoc} = gen_sctp:connect
      (S, Host, Port, [{sctp_initmsg,#sctp_initmsg{num_ostreams=5}}]),
  io:format("Connection Successful, Assoc=~p~n", [Assoc]),
  
  io:write(gen_sctp:send(S, Assoc, 0, <<"Test 0">>)),
  io:nl(),
  timer:sleep(10000),
  io:write(gen_sctp:send(S, Assoc, 5, <<"Test 5">>)),
  io:nl(),
  timer:sleep(10000),
  io:write(gen_sctp:abort(S, Assoc)),
  io:nl(),
  timer:sleep(1000),
  gen_sctp:close(S). 

ただサンプルを動かしてみたよというだけです:-P