Home > 3月 2nd, 2008

2008.03.02

Ruby/EventMachineによるサーバの例

最近、Ruby/EventMachineというライブライがおもしろくて良く使っています。EventMachineは、イベントドリブンで非同期I/O処理を行うためのライブラリで、一部 C++ で書かれていて高速動作するのが特徴です。

EventMachine のインストール

rubygems を使うのが簡単です。

$ gem install eventmachine

EventMachineの使い方

ごく簡単な例:

require 'rubygems'
require 'eventmachine'

EventMachine.run {
  EventMachine.start_server('localhost', 7000, EventMachine::Connection)
}

EventMachine.run はイベント待ちの無限ループを行います。ブロックの中身はイベント待ちループの初期化のあと、ループに入る前に呼ばれます。

EventMachine.start_server は、指定TCPポートで待ち受けるサーバを登録します。3つ目の引数は、イベント発生時にコールバックを処理するクラスまたはモジュールを指定します。
EventMachineのイベント待ちループで、新しい接続(コネクション)が発生すると、ここで指定したクラスのインスタンスが生成され、イベントに応じてそのインスタンスオブジェクトのメソッドが呼び出されます。モジュールを指定した場合は EventMachine::Connectionにmix-inされます。EventMachine::Connectionは元々EventMachineにあるベースとなるクラスです。

上記のスクリプトを実行するとイベント待ちループにはいるので、別の端末ウィンドウを開いて telnet 等で次のように接続します。

$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

なにか文字を入力して Enter を押すと、サーバを起動した端末の方に

............>>>5
............>>>7

などと表示されます。数字は入力した行の文字数です。実際に入力した文字より2多いと思いますが、これは行末の “\r\n” も含めて数えているからでしょう。このように EventMachine::Connectionにはデフォルトで受け取った各行の長さをSTDOUTに出力するコールバックルーチンが定義されています。実際に使うときには EventMachine::Connectionを継承したクラスをつくるか、必要なメソッドを定義したモジュールを指定することになります。

Echoサーバの例

Echoサーバとは、クライアントからの入力をそのまま出力して返すものです。先ほどの例に少し手を加えてEchoサーバを作ってみます。

require 'rubygems'
require 'eventmachine'

module MyHandler
  def receive_data data
    send_data(">> "+data)
  end
end

EventMachine.run {
  EventMachine.start_server('localhost', 7000, MyHandler)
}

新たにMyHandlerというハンドラを定義して、それをstart_serverの引数に渡しています。receive_dataは入力があったときに呼び出されるメソッドで、引数の変数に受け取ったデータが入ります。send_dataは出力するためのメソッドで、ここでは入力の先頭に”>> “を付加してそのまま送り返しています。

これは非常に簡単な例ですが、これだけで複数のクライアントから同時に接続されても正しく動くサーバが簡単に作れます。非同期入出力をするプログラムを作る際には便利なライブラリです。