スポンサーリンク

2016年4月18日

Using gen_udp module in elixir

とある錬金術師の万能薬(Elixir)

Goal

  • gen_udpの簡単なサンプルを実装する

Dev-Environment

  • OS: Windows8.1
  • Erlang: Eshell V7.3, OTP-Version 18.3
  • Elixir: v1.2.3

Using gen_udp module in elixir

gen_udpを使ってみたいと思います。
pingと文字列を渡して、pongと文字列を返すだけの簡単なサンプルの実装になります。
(ローカルホスト内で行っています)

gen_udp module sample

コネクションレスなUDPを使ってサーバとクライアントで通信を取ってみましょう。
全体の処理における流れは以下のようになります。
  1. [server]:gen_udp.open/2でUDPソケットをオープンにする。
  2. [client]:gen_udp.open/2でUDPソケットをオープンにする。
  3. [client]:gen_udp.send/4でサーバへデータを送信する。
  4. [server]クライアント側からのデータを受信し処理する。
  5. [server]:gen_udp.send/4でクライアント側へデータを送信する。
  6. [client]サーバ側からのデータを受信し処理する。(応答が確実ではないのでタイムアウトを設定しています)
  7. [client]:gen_udp.close/1でソケットを閉じる。
ざっと処理を書いていくとこんな感じになります。
サーバの実装は以下のようになります。

File: simple_udp_server.ex

defmodule SimpleUdpServer do
  def start_server do
    {:ok, socket} = :gen_udp.open(1234, [:binary])
    loop
  end

  defp loop do
    receive do
      {:udp, socket, host, port, bin} ->
        :io.format("server receive binary = ~p~n", [bin])
        str = :erlang.binary_to_term(bin)
        :io.format("server unpacked = ~p~n", [str])
        :gen_udp.send(socket, host, port, :erlang.term_to_binary('pong'))
        loop
    end
  end
end
次は、クライアントの実装になります。

File: simple_udp_client.ex

defmodule SimpleUdpClient do
  def ping do
    {:ok, socket} = :gen_udp.open(4321, [:binary])
    :ok = :gen_udp.send(socket, 'localhost', 1234,
                        String.to_char_list("ping") |> :erlang.term_to_binary)

    value = receive do
      {:udp, _socket, _, _, bin} ->
        :io.format("Client received binary = ~p~n", [bin])
        str = :erlang.binary_to_term(bin)
        :io.format("Client result = ~p~n", [str])
        {:ok, str}
    after
      2_000 -> :error
    end

    :gen_udp.close(socket)
    value
  end
end
gen_tcpと同じく注意点としては、バイナリでやり取りしているのでバイナリへ変換していることと、
stringではなく、char_listで送っている点です。
またgen_tcpと違って、”socket closed”のメッセージを受け取ることを考えなくてよい。
実行してみましょう。ターミナルが二つ必要になります。

Example:

  • ターミナル1(Server)
iex> SimpleUdpServer.start_server
...

# ターミナル2を実行すると下記のように出力される
server receive binary = <<131,107,0,4,112,105,110,103>>
server unpacked = "ping"
  • ターミナル2(Client)
iex> SimpleUdpClient.ping
Client received binary = <<131,107,0,4,112,111,110,103>>
Client result = "pong"
{:ok, 'pong'}

Note:

こっちもinetモジュールを使って色々とアクセス元の情報を取得できる。

Bibliography

人気の投稿