IT・技術研修ならCTC教育サービス

サイト内検索 企業情報 サイトマップ

研修コース検索

コラム

Ruby & Rails

CTC 教育サービス

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes 

第13回 WebSocketでサーバプッシュ その2 〜EM-WebSocket〜 (松永紘) 2014年4月

 3/14にRails4.0.4がリリースされました(*1)。このアップデートは多くの機能改修やバグフィックスが含まれています。その中にはRuby2.1.1の不具合(*2)に対するフィックスも含まれていますので、該当バージョンをお使いの方はアップデートすることをお勧めいたします。

 さて、前回はWebSocketの概要について書いてまいりました。今回はその続きとして、実際にWebSocketを使ってみたいと思います。
 WebSocketのライブラリとしてはJavaScriptで実装されたSocket.IO(*3)が有名ですが、本コラムは一応(!)「Ruby、Rails関連コラム」ですので、ここではRubyで実装されたWebSocketのライブラリ、EM-WebSocket(*4)をご紹介いたします。

 動作環境は以下の通りです。

  • Mac OS X 10.9.2
  • Chrome 33
  • Ruby 2.1.1
  • EM-WebSocket : 0.5.0

 なおEM-WebSocketは、Windowsでのインストール時にエラーが発生してインストールできないようですのでご注意ください(*5)。

EM-WebSocket

 EM-WebSocketとは、EventMachine(*6)をベースにしたRuby上で動作するWebSocketサーバです。以下のようにしてインストールします。

gem install em-websocket

 インストールが完了したら実際に使ってみましょう。

require "em-websocket"

EM::WebSocket.start(host: "localhost", port: 3000) do |ws_conn| # ここに処理を記述 end

 上記ソースコードのEM::WebSocket.start(*7)ブロック内に通信確立後の処理を記述していきますが、とりあえずこのままでもWebSocketサーバを起動できるので実行してみます(*8)。

fig01

 実行後はクライアントサイドを作ります。こちらもとりあえず最低限の動作確認ができるコードにしています。

<!DOCTYPE html>
<html>
  <head>
    <title>EM-WebSocket Test</title>
  </head
  <body>
    <script>
      new WebSocket("ws://localhost:3000")
    </script>
  </body>
</html>

 作成後、作ったファイルをChromeで開きます。とはいっても当たり前ながら画面は真っ白のままですので、Chromeの開発者ツールを使ってWebSocketの通信が確立していることを確認します。
 開発者ツールを開いたら、Networkタブを選択しタブ内左部の「localhost」をクリックします。するとヘッダ情報が表示され、WebSocket通信が確立していることが確認できます(*9)。

fig02

 EM::WebSocket.startブロックの引数(*10)にはEventMachine::WebSocket::Connectionオブジェクトが渡されます。これを用いてWebSocket通信時の処理を記述します。
 以下にEventMachine::WebSocket::Connectionでよく使用するメソッドを示します。

メソッド名 説明
onopen(&block) WebSocket通信が確立された際に行う処理を、引数となるブロック内に記述する
onclose(&block) WebSocket通信が終了した際に行う処理を、引数となるブロック内に記述する
onmessage(&block) クライアントからメッセージが送られてきた際に行う処理を、引数となるブロック内に記述する
send(data) クライアントへデータを送信する
close(code =nil, body = nil) クライアントとの接続を(サーバサイトから)終了する

 ご紹介の最後に、WebSocketの例としてはありがちではありますがEM-WebSocketを使ってチャット機能を実装してみます。
 クライアントサイドの実装は以下の通りです(*11)。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>EM-WebSocket Chat Sample</title>
  </head>
  <body>
    <!-- チャット表示部分 -->
    <ul id="chat_area">
    </ul>

<!-- コメントフォーム --> <input id="comment" type="text"> <input id="send" type="button" value="send">
<script> var ws = new WebSocket("ws://localhost:3000");
// メッセージ受信時の処理 ws.onmessage = function(event){ var message_li = document.createElement("li"); message_li.textContent = event.data;
document.getElementById("chat_area").appendChild(message_li); };
// メッセージ送信時の処理 document.getElementById("send").onclick = function(){ var comment = document.getElementById("comment").value;
ws.send(comment); }; </script> </body> </html>

 サーバサイドとなるRubyスクリプトは以下の通りです(*11)。

require "em-websocket"

connections = []
EM::WebSocket.start(host: "localhost", port: 3000) do |ws_conn| ws_conn.onopen do # 接続してきたコネクションを格納 connections << ws_conn end
ws_conn.onmessage do |message| # 全てのコネクションに対してメッセージを送信 connections.each{|conn| conn.send(message) } end end

 完成したらRubyスクリプトを実行し、HTMLをブラウザで開いてみましょう。2つのブラウザを表示し、片方のブラウザでコメントを入力してみるともう片方にも即座に反映されることが分かるかと思います。

fig03

 1点だけ補足を入れると、EventMachine::WebSocket::Connection#sendはそのオブジェクトが保持しているWebSocketコネクションにしかデータを送信しません。ブロードキャストのように全てのコネクションへデータを送る場合には、コネクションを保持するオブジェクト全てのsendを呼ぶ必要があります。
 そのためここでは、onopenのブロック内でEventMachine::WebSocket::Connectionオブジェクトをconnectionsという配列に格納し、onmessageのブロック内でその配列内全てのオブジェクトに対してsendを行っています。

 なお、EM-WebSocketには複数のコネクションに対して処理を行うためのクラスEventMachine::Channelが用意されており、それを使用して以下のように記述することもできます。

require "em-websocket"

# 配列ではなくEventMachineオブジェクトを生成 connections = EM::Channel.new
EM::WebSocket.start(host: "localhost", port: 3000) do |ws_conn| ws_conn.onopen do # EventMachine#subscribeを用い、コネクションオブジェクトと処理を登録 connections.subscribe{|message| ws_conn.send(message) } end
ws_conn.onmessage do |message| # onopen内で登録した処理を呼び出し connections.push(message) end end
まとめ

 簡単ではありますが、EM-WebSocketのご紹介いたしました。WebSocketと聞くとなんだか難しそうなイメージがありましたが、このライブラリを使用すると手軽にWebSocketを扱うことができそうですね。
 Githubページにも詳しい説明が掲載されていますので、是非ご覧ください。
 次回はRails上で動作するWebSocketライブラリ、Websocket-Railsをご紹介したいと思います。

 それでは、Enjoy Ruby!

注釈

*1http://weblog.rubyonrails.org/2014/3/14/Rails-4-0-4-has-been-released/

*2https://www.ruby-lang.org/ja/news/2014/03/10/regression-of-hash-reject-in-ruby-2-1-1/

*3http://socket.io/

*4https://github.com/igrigorik/em-websocket

*5https://github.com/igrigorik/em-websocket/issues/102

*6https://github.com/eventmachine/eventmachine

*7:ちなみにEMはEventMachineの別名です。

*8:ここではPryで実行しています。

*9:Networkタブに何も表示されない場合は、ページを再読み込みしてください。

*10:ここではws_connのことですね。

*11:クライアントサイド、サーバサイドともに最低限度のコードしか書いていません。実際にはコネクションの死活監視などの処理も必要でしょう。

 


 

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes