12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

今からでも間に合うErlang入門

Posted at

Ubuntu 16.04でErlangのインストールから簡単なサンプルアプリケーションの作成まで行ってみます。

Erlang開発環境構築(初期設定)

依存ファイルをインストール

sudo apt-get install build-essential libncurses5-dev openssl libssl-dev
sudo apt-get install curl git-core

Erlangのバージョン管理、Kerlをインストール

mkdir -p ~/local/bin
cd ~/local/bin
curl -O https://raw.githubusercontent.com/kerl/kerl/master/kerl
chmod a+x kerl

kerlでErlang 19.1をインストール

./kerl list releases
./kerl install 19.1 19.1
./kerl build 19.1 19.1
./kerl install 19.1 ~/erlang/19.1

インストールした Erlang 19.1 を有効化します。

. ~/erlang/19.1/activate

whichでerlコマンドが使える事が分かり開発環境が整いました。

which erl
# /home/username/erlang/19.1/bin/erl

簡単なネットワークアプリケーションの開発

Erlangで簡単なhttpdサーバを作ってみます。

ビルドツールのrebarを使う

rebarを使うとコンパイル、テスト、配布用のtar.gzの作成などがコマンド一つでできるので便利です。

mkdir project
cd project
wget https://s3.amazonaws.com/rebar3/rebar3
chmod 0755 rebar3

rebarで定形ファイル作成

./rebar3 new app httpd
# ===> Writing httpd/src/httpd_app.erl
# ===> Writing httpd/src/httpd_sup.erl
# ===> Writing httpd/src/httpd.app.src
# ===> Writing httpd/rebar.config
# ===> Writing httpd/.gitignore
# ===> Writing httpd/LICENSE
# ===> Writing httpd/README.md

実装

今回は簡単なhttpサーバを実装してみます。
処理の流れは以下のイメージ。

  1. httpd_tcp_listener が新規接続してきたHTTPクライアントを受付
  2. httpd_tcp_worker_sup の start_child() で1つのTCPストリームを処理するプロセスを起動(Erlangのプロセスはマイクロスレッドを意味します)
  3. 起動したプロセスは httpd_tcp_worker の start_link() でTCPストリームからHTTPリクエストを読み込み、HTTPレスポンスを書き込む

以下の3ファイルを追加します。

src/httpd_tcp_listener.erl
-module(httpd_tcp_listener).

-export([start_link/0]).

start_link() ->
    Pid = spawn_link(fun init/0),
    {ok, Pid}.

init() ->
    Port = 8888,
    Backlog = 10244,
    Options = [binary,
              inet6, % support both ipv4 and ipv6
              {active, false},
              {reuseaddr, true},
              {backlog, Backlog}
             ],
    {ok, Listen} = gen_tcp:listen(Port, Options),
    accept(Listen).

accept(Listen) ->
    case gen_tcp:accept(Listen) of
        {ok, Socket} ->
            {ok, Pid} = httpd_tcp_worker_sup:start_child(Socket),
            gen_tcp:controlling_process(Socket, Pid);
        {error, Reason} ->
            io:format("fail accept ~p~n", [Reason])
    end,
    accept(Listen).
src/httpd_tcp_worker.erl
-module(httpd_tcp_worker).

-export([start_link/1]).

start_link(Socket)->
    Pid = spawn_link(fun() -> process(Socket, 0, 30 * 1000) end),
    {ok, Pid}.

process(Socket, Size, Timeout) ->
    case gen_tcp:recv(Socket, Size, Timeout) of
        {ok, Packet} ->
            Response = response(Packet),
            gen_tcp:send(Socket, Response),
            gen_tcp:close(Socket);
        {error, Reason} ->
            io:format("fail recv ~p~n", [Reason]),
            gen_tcp:close(Socket)
    end.

response(_Request) ->
    <<"HTTP/1.0 200 OK\r\nDate: Tue, 25 Oct 2016 10:21:33 GMT\r\nConnection: close\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 11\r\n\r\nhello world">>.
src/httpd_tcp_worker_sup.erl
-module(httpd_tcp_worker_sup).

-export([start_link/0, start_child/1, init/1]).

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

start_child(Socket) ->
    supervisor:start_child(?MODULE, [Socket]).

init([]) ->
    Children = [
                {"httpd_tcp_worker", {httpd_tcp_worker, start_link, []}, temporary, 5, worker, []}
               ],
    {ok, {{simple_one_for_one, 0, 1}, Children}}.

また httpd_sup.erl の init([]) を編集し、追加実装した部分の起動処理を加えます。

src/httpd_sup.erl
%% ...(省略)...
init([]) ->
    Children = [
                {"httpd_tcp_listener", {httpd_tcp_listener, start_link, []}, permanent, 5, worker, []},
                {"httpd_tcp_worker_sup", {httpd_tcp_worker_sup, start_link, []}, permanent, 5, supervisor, []}
               ],
    {ok, { {one_for_all, 0, 1}, Children} }.

動作確認

アプリケーションの実装が終わったので起動してみます。

../rebar3 compile && erl -pa _build/default/lib/*/ebin -eval 'application:start(httpd).' -noshell

ブラウザからアクセスするとhello worldと表示されました。
hello_world.png

まとめ

Erlangでネットワーク・サーバを実装するのは難しくない印象です。
ただsupervisorを理解して使いこなすのはある程度の経験が必要そうです。

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?