Kevin
Kevin

Reputation: 37

how to use gen_sctp:send/3

I am making an example when using gen_sctp create soscket and associates in server-client model.

In server side:

{ok,serverSocket} = gen_sctp:open(1234,[{ip,{127,0,0,1}},{reuseaddr,true},{active,true}]).

ok = gen_sctp:listen(S,true).

In client side:

{ok,Client} = gen_sctp:open(1243,[{ip,{127,0,0,1}},{reuseaddr,true}]).

{ok,Ass} =  gen_sctp:connect(S,{127,0,0,1},1234,[{active,true}]).

And then client send message to server by send/4:

gen_sctp:send(S,Ass,2,<<"hellooooo">>).

And message receive in server side:

{sctp,#Port<0.6126>,
                {127,0,0,1},
                1243,
                {[{sctp_sndrcvinfo,2,1,[],0,0,0,1409953138,0,18}],
                 <<"hellooooo">>}}

So how can server can reply message to client by send/3?

Thanks and Best Regards,

Tran.

Upvotes: 1

Views: 489

Answers (1)

reith
reith

Reputation: 2088

gen_sctp:send/3 is like gen_sctp:send/4 but you can set more flags and options. You have already used gen_sctp:send/4 in client code (while you messed around with client and server sockets):

{ok, Assoc} = gen_sctp:connect(ClientSocket, {127,0,0,1}, 1234,[{active,true}]).
gen_sctp:send(ClientSocket, Assoc, 2, <<"hellooooo">>).

And Assoc is of sctp_assoc_change record type while gen_sctp:send/4 looks just for assoc_id if you provide sctp_assoc_change. So currently providing #sctp_assoc_change{} or just association id behave exactly same.

And how one can find out association id of client in server? It's provided in message which server received:

{sctp,#Port<0.6126>,
                {127,0,0,1},
                1243,
                {[{sctp_sndrcvinfo,2,1,[],0,0,0,1409953138,0,18}],
                 <<"hellooooo">>}}

#sctp_sdnrcvinfo{} record has fields telling association id and stream number which data is received from. You can get current association id from assoc_id field and pass it to another gen_sctp:send/4:

gen_sctp:send(ServerSocket, AssocID, 2, <<"welcome!">>).

Stream number of 2 probably won't make it fail because by default gen_sctp:open makes 10 incoming and outgoing streams, but you can safely provide 0 as stream number.

Here is an example of sending and receiving data with sctp:

#!/usr/bin/escript

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

server_loop(Socket) ->
  receive
    {sctp, Socket, _FromIP, _FromPort, {[#sctp_sndrcvinfo{assoc_id=AssocID}],
                                        Payload}} ->
      gen_sctp:send(Socket, #sctp_sndrcvinfo{assoc_id=AssocID, stream=0},
                    <<"pong">>),
      % or less complex gen_sctp:send/4
      gen_sctp:send(Socket, AssocID, 0, <<"pong">>);
    Rest ->
      io:format("server got unhandled message ~w~n", [Rest])
  end,
  server_loop(Socket).

create_server_socket() ->
  {ok, Socket} = gen_sctp:open(1234, [{ip,{127,0,0,1}}, {reuseaddr,true},
                                      {active,true}]),
  gen_sctp:listen(Socket, true),
  {ok, Socket}.

run_server() ->
  Spawner = self(),
  spawn_link(fun() ->
    {ok, Socket} = create_server_socket(), Spawner ! ready, server_loop(Socket)
  end),
  receive
    ready ->
      io:format("server is up~n"),
      ok
    after 100 ->
      throw(server_timeout)
  end.

ping_server() ->
  {ok, Socket} = gen_sctp:open(1243, [{ip,{127,0,0,1}}, {reuseaddr, true}]),
  {ok, AssocChange} = gen_sctp:connect(Socket, {127,0,0,1}, 1234, [{active, true}]),
  gen_sctp:send(Socket, AssocChange, 2, <<"ping">>),
  receive
    {sctp, Socket, _FromIP, _FromPort, {[#sctp_sndrcvinfo{}], Payload}} ->
      io:format("client got payload ~p~n", [Payload])
    after 2000 ->
      throw(client_timeout)
  end.

main([]) ->
    run_server(),
    ping_server().

Upvotes: 2

Related Questions