Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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を理解して使いこなすのはある程度の経験が必要そうです。

tadokoro
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした