[HTML5] WebSocketを使ってスライドショーをつくってみる

2013.11.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

つい先日まではリアルタイム通信といえばAjaxポーリングやCometを使用していました。
しかし、最近はノータイムでWebSocket使用を決定することが多くなっています。
Googleトレンドを見てもわかるように、WebSocketは数年前から日を追うごとに注目されてきおり、
今ではリアルタイム通信を実現するためのスタンダードな技術となっているといっても過言ではありません。
いままでWebSocket採用の障壁だったIE対応についても、去年から今年にかけてHTML5に対応し、WebsSocketも動くようになりました。

本記事ではWebSocketやそれに関連する技術の簡単な解説、Websocketを使用したサービスについて紹介し、
WebSocketを使った簡単なデモの説明を行います。

WebSocketとそれに関連する概要

まずはWebSocketおよびそれに関する技術について簡単におさらいしておきます。

WebSocketとは

WebSocketとは、ネットワーク用通信規格であり、
インターネットの標準化団体(W3CとIETF)が関与している、サーバー/ブラウザ間通信のための双方向通信用技術規格です。
元々はHTML5の仕様の一部として策定されていましたが、現在はHTML5から切り離された規格として策定が進んでいます。

WebSocketを使用すると、従来の双方向通信(XMLHttpRequest/Comet)が抱えていた欠点を
解消することができると言われています。
例えば、XMLHttpRequestを使用した通信ではpush配信ではなくポーリングです。
また、Cometの場合ではpush配信ができますが、だいたいの実装では接続に負荷がかかったり、
コネクションを専有してしまうという問題があります。

これに対してWebSocketでは、サーバとクライアントが最初に接続を行った後、その後の通信を全てその接続で行います。
その際にはHTTPより軽量のプロトコルを使用するため、接続/通信のための負荷低減が可能になります。

Websocketの利用例

さて、WebSocketがどういうものか簡単に説明しましたが、どのように利用されているのでしょうか。
実際にWebSocketを使用したサービス/ツール等の利用例をいくつかご紹介します。

Cassandraノードの値をリアルタイムでチェック

Cassandra用ツール

Cassandraの全ノードのPendingTask値(処理の滞留数)をリアルタイムでチェックする、
WebSocketを使用した監視ツールです。
これを使用すれば、Cassandraのどのノードで処理が詰まっているかをひと目で見ることができます。

タブレットでTV操作を行う「りもこんプラス」

ここ で詳細に説明されているのですが、ひかりTVのりもこんプラスというサービスもWebSocketを使用しています。
これはセカンドスクリーンとして、iPad等のタブレットをテレビのリモコン代わりに使うことのできるサービスです。
WebSocketを用いて、リアルタイムでTV-タブレット間の通信を行います。

ゆっくりボイスでチャット

yukkurichat1

以前、弊社ブログにて解説した記事、
WebsocketとAquesTalkでゆっくりボイスのチャットをつくろう
というサンプルアプリでも、WebSocketを使用しています。
このアプリでは、入力された文字を音声合成ソフトによってwavファイル化し、音声再生のための情報をWebSocketで共有しています。

いくつか紹介しましたが、これ以外にもログ監視やアクセス分析、VNCクライアントといったサービスについても、
WebSocketを使用して実現されているものもあったりします。

本記事では、WebSocketを使用して、閲覧者全員が同じタイミングでスライドを見られるような、
スライドショー的なデモを作成してみましょう。

node.jsでWebsocketを使用したサンプルをつくってみる

では、ここからnode.jsとsocket.ioを使って、WebSocketを使ったアプリをつくっていきます。
まずはnode.jsとsocket.ioの簡単な説明です。

node.jsとは

Node.js

node.jsは弊社ブログで何度も取り上げられています。
簡単に言えば、「JavaScriptを使った軽量かつノンブロッキングIOなサーバサイド実装」です。
V8と呼ばれるJavaScriptエンジンをサーバ上で実行できるように多数の機能を追加したもので、
軽量かつハイパフォーマンスで多数のリクエストを処理するアプリケーションを構築できます。
node.jsについては、ググれば詳細な記事が多数見つかりますのでご確認ください。

socket.ioとは

socketio

socket.ioはnode.js用モジュールで、サーバサイドライブラリとクライアントライブラリがセットになって提供されています。
ブラウザが対応したさまざまな接続方法(WebSocket,ポーリング,Flash Socket等)を自動で選択してくれるので、
古いブラウザからスマフォ用ブラウザまで、ブラウザの差異を気にせず実装することができます。

また、接続したクライアントを判別して、任意のクライアントにイベントを送るRooms機能や、
イベント毎に名前空間を定義する機能を持っています。あとはexpressフレームワークとの連携もできるようになっていて、
nod.jsでWebSocketを使用する際には最初に選択肢にあがるモジュールではないでしょうか。

環境構築方法

今回使用した動作環境は以下のとおりです。

  • OS : MacOS X 10.9
  • node.js : v0.10.21
  • ブラウザ : Google Chrome 30.0.1599.101

node.jsについては公式ページ等を参考にしてインストールしておいてください。

WebSocketを使用したスライドショーをつくろう

では、socket.ioを使ってnodeアプリをつくっていきましょう。
スライドショーと名前がついてますが、実際はWebSoketを使用して画面に表示する画像を共有するだけのシンプルなアプリです。

1.モジュールのインストールとひな形作成

モジュールのインストールとアプリのひな形を作成します。
まずはexpressをグローバルインストールし、その後expressコマンドでひな形を生成します。

% mkdir slide && cd slide
% npm install -g express
% express

生成されたアプリで使用するモジュールを追加インストールしましょう。

% npm install
% npm install socket.io jade

2.画像ファイルを配置

このアプリでは接続したユーザーの表示する画像を共有するためにWebSocket通信を行います。
public/imagesに下記のような名前で画像を置いておきましょう。これがスライドになります。

  • slide-1.png
  • slide-2.png
  • slide-3.png

3.サーバサイドのプログラムを修正

次に、生成されたapp.jsを次のように修正しましょう。

・
・
・
app.get('/', routes.index);
app.get('/users', user.list);

//ここから修正
var server = http.createServer(app);

server.listen(app.get('port'), function () { //add
    console.log("Express server listening on port " + app.get('port'));
});

var socketIO = require('socket.io');
//※1
var io = socketIO.listen(server);

io.sockets.on('connection', function (socket) {
    console.log("connection");
    //※2
    socket.on('showPicture', function (data) {
        io.sockets.emit('showPicture', { page: data.page});
    });
    socket.on('disconnect', function () {
        console.log("disconnect");
    });
});

app.get関数でルートの定義をしている後を、上のように修正します。
http.createServerで作成されたHTTPサーバを、socket.ioオブジェクトのlisten関数でラップします。(※1)

また、socket.ioオブジェクトは「showPicture」という名前のメッセージを受け取イベントをクライアントから受け取ります。(※2) このイベントでは、表示するスライドのページをうけとり、そのページ番号を全ユーザーにブロードキャストしています。

4.クライアントプログラムの作成

サーバサイドの修正がおわったら、クライアントの修正も行います。views/layout.jadeを次のように記述しましょう。
socket.io用のjsとjqueryを読み込みます。

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    script(src="http://codeorigin.jquery.com/jquery-2.0.3.min.js")
    script(src="/socket.io/socket.io.js")
      body
    block content

views/index.jadeも修正します。 img画像(スライド)と戻る/進むボタンがおいてあるシンプルなページを作成します。
最後の行で、次に作成するslide.jsを読も込みます。

extends layout

block content
  h1= title

  img(id="image",src="/images/slide-1.png",width="300px",height="200")
  br
  input(id="prev",value="prev",type="button")
  input(id="next",value="next",type="button")

  script(src="/javascripts/slide.js")

最後に、public/javascripts/slide.jsファイルを作成します。
prevボタン/nextボタンを押すと、次のページ表示のための情報をWebSocketでサーバに送ります。
サーバは表示するページ番号をうけとり、showPictureメッセージをブロードキャストします。
クライアントはshowPictureメッセージを受け取ると、表示している画像を切替えます。

$(function () {

//表示するページ番号 var pageNumber = 1;

//prevボタンを押したときの処理 $("#prev").click(function () { if(pageNumber > 1) { pageNumber--; } socket.emit('showPicture', { page: pageNumber }); });

//nextボタンを押したときの処理 $("#next").click(function () { if(pageNumber < 3) { pageNumber++; } socket.emit('showPicture', { page: pageNumber }); }); //socket.ioの初期化処理 var socket = io.connect('http://localhost:3000'); socket.on('connect', function (msg) { console.log("connect"); }); //showPictureメッセージをうけとったときの処理 socket.on('showPicture', function (msg) { pageNumber = msg.page; console.dir(msg); $("#image").attr("src","/images/slide-" + pageNumber + ".png"); }); }); [/javascript]

では、作成したアプリを動かしてみましょう。

%node app.js
info  - socket.io started
Express server listening on port 3000

http://localhost:3000に複数ブラウザを立ち上げてアクセスしてみてください。
prev/nextボタンをどれかのブラウザで押すと、すべてのブラウザ画面で同じスライドが表示されます。
※このデモの場合、誰がボタンを押してもスライドが変更されてしまうので注意

slide-demo

まとめ

さて、今回はnode.js + socket.ioを使用してスライドショーを作成してみました。
双方向通信が簡単に実装できることがわかったと思います。
なお、socket.ioは0.9以降に更新が滞っていますが、1.0も動かすことは可能です
0.9から大きな変更が入っていますが、接続がより安定していたりしますし、
そのうち1.0も正式版もリリースされる(はず)なので、1.0の採用も視野にいれてみてください。

参考サイトなど