programming erlang ch14 2 - andstudy/forge GitHub Wiki

Chapt 14. ์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

TCP ์‚ฌ์šฉํ•˜๊ธฐ

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœํ•ด๋‚ด๊ธฐ

  • socket_examples.erl

      nano_get_url() ->
          nano_get_url("www.google.com").
      
      nano_get_url(Host) ->
          {ok,Socket} = gen_tcp:connect(Host,80,[binary, {packet, 0}]), %% (1)
          ok = gen_tcp:send(Socket, "GET / HTTP/1.0\r\n\r\n"),  %% (2)
          receive_data(Socket, []).
      
      receive_data(Socket, SoFar) ->
          receive
      	{tcp,Socket,Bin} ->    %% (3)
      	    receive_data(Socket, [Bin|SoFar]);
      	{tcp_closed,Socket} -> %% (4)
      	    list_to_binary(reverse(SoFar)) %% (5)
          end.
    
  • ์‹คํ–‰ํ•ด๋ณด๊ธฐ

      socket_examples:nano_get_url().
      RESULT = socket_examples:nano_get_url("www.naver.com").
      io:format("~p~n",[RESULT]).
      string:tokens(binary_to_list(RESULT),"\r\n").          
    

๊ฐ„๋‹จํ•œ TCP์„œ๋ฒ„

  • eval ์„œ๋ฒ„

      start_nano_server() ->
          {ok, Listen} = gen_tcp:listen(2345, [binary, {packet, 4},  %% (6)
      					 {reuseaddr, true},
      					 {active, true}]),
          {ok, Socket} = gen_tcp:accept(Listen),  %% (7)
          gen_tcp:close(Listen),  %% (8)
          loop(Socket).
      
      loop(Socket) ->
          receive
      	{tcp, Socket, Bin} ->
      	    io:format("Server received binary = ~p~n",[Bin]),
      	    Str = binary_to_term(Bin),  %% (9)
      	    io:format("Server (unpacked)  ~p~n",[Str]),
      	    Reply = lib_misc:string2value(Str),  %% (10)
      	    io:format("Server replying = ~p~n",[Reply]),
      	    gen_tcp:send(Socket, term_to_binary(Reply)),  %% (11)
      	    loop(Socket);
      	{tcp_closed, Socket} ->
      	    io:format("Server socket closed~n")
          end.
    
  • ํด๋ผ์ด์–ธํŠธ

      nano_client_eval(Str) ->
          {ok, Socket} = 
      	gen_tcp:connect("localhost", 2345,
      			[binary, {packet, 4}]),
          ok = gen_tcp:send(Socket, term_to_binary(Str)),
          receive
      	{tcp,Socket,Bin} ->
      	    io:format("Client received binary = ~p~n",[Bin]),
      	    Val = binary_to_term(Bin),
      	    io:format("Client result = ~p~n",[Val]),
      	    gen_tcp:close(Socket)
          end.
    
  • ์„œ๋ฒ„ ์‹คํ–‰ํ•˜๊ธฐ

      c("socket_examples").
      c("lib_misc").
      socket_examples:start_nano_server().
    
  • ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰ํ•˜๊ธฐ

      c("socket_examples").
      socket_examples:nano_client_eval("list_to_tuple([2+3*4,10+20])").
    

์„œ๋ฒ„ ๊ฐœ์„ ํ•˜๊ธฐ

  • ์ˆœ์ฐจ์„œ๋ฒ„ - ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ ‘์†๋งŒ ๋ฐ›๋Š” ์„œ๋ฒ„

      start_seq_server() ->
        {ok, Listen} = gen_tcp:listen(...),
        seq_loop(Listen).
      
      seq_loop(Listen) ->
        {ok, Socket} = gen_tcp:accept(Listen),
        loop(Socket),
        seq_loop(Listen).
      
      loop(..) -> %..์›๋ž˜ ๋กœ์ง
    
  • ๋ณ‘๋ ฌ์„œ๋ฒ„ - ๋™์‹œ์— ๋‹ค์ˆ˜์˜ ๋ณ‘๋ ฌ ์ ‘์†์„ ๋ฐ›๋Š” ์„œ๋ฒ„

      start_parallel_server() ->
        {ok, Listen} = gen_tcp:listen(...),
        spawn( fun() -> par_connect(Listen) end ).
      par_connect(Listen) ->
        {ok, Socket} = gen_tcp:accecpt(Listen),
        spawn( fun() -> par_connect(Listen) end ).
        loop(Socket).
      
      loop(..) -> %..์›๋ž˜ ๋กœ์ง
    

์ œ์–ด์ด์Šˆ

  • ์–ผ๋žญ ์†Œ์ผ“์˜ ์„ธ๊ฐ€์ง€ ๋ชจ๋“œ
์˜ต์…˜ ๋ชจ๋“œ์„ค๋ช… ๋ฐ์ดํ„ฐ ์ˆ˜์‹ 
{active,true} ๋Šฅ๋™์  ๋ฉ”์„ธ์ง€ ์ˆ˜์‹ (๋…ผ๋ธ”๋กœํ‚น) {tcp, Socket, Data} ๋กœ ์ „๋‹ฌ ๋ฐ›์Œ
{active,false} ์ˆ˜๋™์  ๋ฉ”์„ธ์ง€ ์ˆ˜์‹ (๋ธ”๋กœํ‚น) gen_tcp:recv{Socket,N) ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
{active,once} ํ˜ผํ•ฉํ˜• ๋ฉ”์„ธ์ง€ ์ˆ˜์‹ (๋ถ€๋ถ„ ๋ธ”๋กœํ‚น) ํ•œ๋ฒˆ๋งŒ ๋ฐ์ดํ„ฐ๊ฐ€ {tcp, Socket, Data}๋กœ ์ˆ˜์‹ 

๋Šฅ๋™์  ๋ฉ”์„ธ์ง€ ์ˆ˜์‹ (๋…ผ๋ธ”๋กœํ‚น)

    {ok, Listen| = gen_tcp:listen(Port, [..,{active, true}, ..]),
    {ok, Socket} = gen_tcp:accept(Listen),
    loop(Socket).
    loop(Socket) ->
      receive
         {tcp, Socket, Data} ->
              .. do something with the data...
         {tcp_closed, Socket} ->
              ..
      end.

์ˆ˜๋™์  ๋ฉ”์„ธ์ง€ ์ˆ˜์‹  (๋ธ”๋กœํ‚น)

    {ok, Listen| = gen_tcp:listen(Port, [..,{active, false}, ..]),
    {ok, Socket} = gen_tcp:accept(Listen),
    loop(Socket).
    loop(Socket) ->
      case gen_tcp:recv(Socket, N) of
         {ok, B} ->
              .. do something with the data...
              loop(Socket);
         {error, closed} ->
              ..
      end.

ํ˜ผํ•ฉํ˜• ๋ฐฉ์‹(๋ถ€๋ถ„ ๋ธ”๋กœํ‚น)

    {ok, Listen} = gen_tcp:listen(Port, [..,{active, once}, ..]),
    {ok, Socket} = gen_tcp:accept(Listen),
    loop(Socket).
    loop(Socket) ->
       receive
         {tcp, Socket, Data} ->
          ...๋ฐ์ดํ„ฐ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•จ ...
          %% ๋‹ค์Œ๋ฒˆ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜์‘ ์ค€๋น„๊ฐ€ ๋˜๋ฉด
           inet:setopts(Socket, [{active,once}]),
          loop(Socket);
         {tcp_closed, Socket} ->
              ..
      end.

๊ทธ ์ ‘์†์€ ์–ด๋””์„œ๋ถ€ํ„ฐ ์™”๋Š”๊ฐ€

@spec inet:peername(Socket) -> {ok, {IP_Address, Port}) | {error,Why}

์†Œ์ผ“๊ณผ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

    error_test() ->
        spawn(fun() -> error_test_server() end),
        lib_misc:sleep(2000),
        {ok,Socket} = gen_tcp:connect("localhost",4321,[binary, {packet, 2}]),
        io:format("connected to:~p~n",[Socket]),
        gen_tcp:send(Socket, <<"123">>),
        receive
    	Any ->
    	    io:format("Any=~p~n",[Any])
        end.
    
    error_test_server() ->
        {ok, Listen} = gen_tcp:listen(4321, [binary,{packet,2}]),
        {ok, Socket} = gen_tcp:accept(Listen),
        error_test_server_loop(Socket).
    
    error_test_server_loop(Socket) ->
        receive
    	{tcp, Socket, Data} ->
    	    io:format("received:~p~n",[Data]),
    	    atom_to_list(Data),
    	    error_test_server_loop(Socket)
        end.

UDP

๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ UDP ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ

  • UDP ์„œ๋ฒ„

      server(Port) ->
      {ok,Socket} = gen_udp:open(Port, {binary}),
      loop(Socket).
      
      loop(Socket) ->
         recive
           {udp, Socket, Host, Port, Bin} ->
               BinReply = ....
               gen_udp:send(Socket, Host, Port, BinReply),
               loop(Socket)
         end.
    
  • UDP ํด๋ผ์ด์–ธํŠธ

      client(Request) ->
        {ok, Socket} = gen_udp:open(0, {binary}),
        ok = gen_udp:send(Socket, "localhost" , 4000, Request),
        Value = receive
                  {udp, Socket, _, _, Bin} -> {ok, Bin}
                after 2000 ->
                    error
                end,
        gen:udp_close(Socket),
        Value
    

UDP ํŒฉํ† ๋ฆฌ์–ผ ์„œ๋ฒ„

  • udp_test.erl

      start_server() ->
          spawn(fun() -> server(4000) end).
      
      %% The server 		  
      server(Port) ->
          {ok, Socket} = gen_udp:open(Port, [binary]),
          io:format("server opened socket:~p~n",[Socket]),
          loop(Socket).
      
      loop(Socket) ->
          receive
      	{udp, Socket, Host, Port, Bin} = Msg ->
      	    io:format("server received:~p~n",[Msg]),
      	    N = binary_to_term(Bin),
      	    Fac = fac(N),
      	    gen_udp:send(Socket, Host, Port, term_to_binary(Fac)),
      	    loop(Socket)
          end.
          
      fac(0) -> 1;
      fac(N) -> N * fac(N-1).
      
      %% The client
      
      client(N) ->
          {ok, Socket} = gen_udp:open(0, [binary]),
          io:format("client opened socket=~p~n",[Socket]),
          ok = gen_udp:send(Socket, "localhost", 4000, 
      		      term_to_binary(N)),
          Value = receive
      		{udp, Socket, _, _, Bin} = Msg ->
      		    io:format("client received:~p~n",[Msg]),
      		    binary_to_term(Bin)
      	    after 2000 ->
      		    0
      	    end,
          gen_udp:close(Socket),
          Value.
    
โš ๏ธ **GitHub.com Fallback** โš ๏ธ