作成2013年9月3日
編集2013年10月18日
リアルタイム双方向通信について
1.リアルタイム双方向通信への期待
httpの世界ではサーバーにリクエストをしなければ、レスポンスが返ってこない。Web2.0以前のWebでは、リクエストの度にページ遷移が発生したが、Ajaxの登場により必要な個所の情報の書き換えが可能となった。また時々刻々と発生する情報をポーリングによってWebから新しい情報を収集するRSSも脚光を浴びた。
最近、だいぶ便利になったWebであるが、効率よく、リアルタイムに、情報を受け取るなどができる新しい技術としてHTML5が登場し、我々を新しいWebのパラダイムへ誘おうとしている。
2.Websocketとは
HTML5はこれからのWebが必要とする新機能がてんこ盛り。その中でも待ち望んでいた機能としてWebsocketによるリアルタイム双方向通信がある(現在、W3Cが標準化を進めている)。Websocketを利用することで、サービス提供者からサービス利用者へ、情報をリアルタイムにPUSHすることができる。Websocketは、最新のPCの各種ブラウザー、スマホのブラウザーで利用することができ(Can I use Web Sockets?)、今後利用がますます拡大すると想定される。
2.1 Websocketによる通信
クライアント側もサーバー側も、(1)socketのopen、(2)相手方からのコネクションを受け、コネクションをopen、その後、(3)、(4)メッセージを送り、送られたメッセージを受け取り、メッセージに対応した処理を行う、(5)コネクションの終了、と言った手順で、リアルタイム双方向通信が実現できる。
Websocketの応用例として、NHKが推進しているHybridcastがある。Hybridcastの受像機では、BMLブラウザーとHTML5ブラウザーが同居し、受像機とスマートデバイス(セカンドスクリーン)がWebsocketでつながるらしい。番組を見ながら、番組連動の情報がセカンドスクリーンにPUSHされる、そんな日がそこまで来ている。
2.2 Websocket(HTML)のコードサンプル
<script type="text/javascript"> var ws = new WebSocket("ws://localhost:3001"); // socketのopen ws.onopen = function(v) { // コネクション接続 console.log("connection is opened."); } ws.onclose = function() { // コネクション切断時 console.log("connection is closed."); }; ws.onmessage = function (data) { // メッセージ受信 getMessage(data.data); } function sendMessage(msg) { // メッセージ送信 ws.send("{message:"+msg+"}"); } </script>
2.3 Websocket(node.js)のコードサンプル
var WebSocketServer = require('ws').Server; var server = http.createServer(function(req, res) { ・・・・ } var wss = new WebSocketServer({server:server}); var connections = []; //websocketの接続 wss.on('connection', function (ws) { connections.push(ws);//WebSocket接続情報の保存 //受信メッセージのブロードキャスト ws.on('message', function (data) { data=JSON.parse(data); var comment = new Object(); comment.message = data.message; comment.date = new Date(); comment.save( function(err, comment) { if (err) { console.log(err); } }); console.log('message:', comment.message); broadcast(JSON.stringify(comment.message)); }); //切断イベント ws.on('close', function () { connections = connections.filter(function (conn, i) { return (conn === ws) ? false : true; }); }); }); //メッセージのブロードキャスト function broadcast(message) { connections.forEach(function (con, i) { con.send(message); }); };
3.Socket.ioについて
Socket.ioは、すべてのクロスブラウザー(例えばIEの古いバージョン) / クロスデバイス上で リアルタイム通信を目指している。一方、WebSocketは古いブラウザー / デバイスを対象としていない。Socket.ioはWebsocketのバイナリーデータの取り扱いなどを取り込み、Websocketを凌駕しようとしているが、もう少し時間がかかりそうである(Socket.io V1.0以降)。
3.1 Socket.ioによる通信
Socket.ioもWebsocketと同様の手順で、リアルタイム双方向通信ができる。上記Websocketのコードサンプルと比べ、差異は少ない。
3.2 Socket.io(HTML)のコードサンプル
<script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript"> var socket = io.connect("http://localhost:3000"); // socketのopen //サーバーから受け取るイベント socket.on("connect", function () { // コネクション接続 console.log("connection is opened."); }) socket.on("disconnect", function (client) { // コネクション切断 console.log("connection is closed."); }); socket.on("message", function (data) { // メッセージ受信 getMessage(data.message); }); function sendMessage(msg) { socket.emit("message", {message:msg}); } </script>
3.3 Socket.io(node.js)のコードサンプル
var socketio = require("socket.io"); var server = http.createServer(function(req, res) { ・・・・ } var io = socketio.listen(server); var member={}; //socket.ioの接続 io.sockets.on("connection", function (socket) { if(!member[socket.id])member[socket.id]=socket.id;//socket.id情報の保存 //受信メッセージのブロードキャスト socket.on("message", function (data) { var comment = new Object(); comment.message = data.message; comment.date = new Date(); comment.save( function(err, comment) { if (err) { console.log(err); } }); console.log('message:', comment.message); socket.broadcast.emit("message", {message:data.message}); }); //切断イベント socket.on("disconnect", function () { console.log("user disconnected "+socket.id); delete member[socket.id]; }); });
4.WebsocketとSocket.ioの違い
Websocketは、W3CがHTML5で規格としてまとめているリアルタイム双方向通信技術であり、作動条件はHTML5対応ブラウザーとなる。一方で、socket.ioは、各種トンランスポートを、各種ブラウザー、各種デバイス上で、作動するリアルタイム双方向通信技術である(公式サイトより、Socket.IO aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms.)。
一般的なプログラマーから見て、WebsocketとSocket.ioの違いはほとんどないが、現時点では、Websocketはバイナリーデータが扱える、Socket.ioは使い易い、など若干の違いがある。
両者の選択については、利用条件、データ転送効率などのベンチマーク評価、プロキシーサーバーが越えられるかなどを含め、調査する必要がある。
リアルタイム双方向通信のデモと言えばチャットでしょ。WebsocketとSocket.ioそれぞれを用いてチャットプログラムを作成した。
今回作成したチャットプログラムは、チャットメッセージをMongoDBに書き込み、Websocket Serverの接続ユーザー同士、Socket.io Serverの接続ユーザー同士でチャットを楽しむことができる。当然であるが、プロトコルが異なるため、WebsocketとSocket.ioが混在した通信はできない。両サーバーともHttpサーバー機能があるため、MongoDBの参照は共にできる。
Websocketでは、node-http-proxy.jsを用いたリバース・プロキシーを設け、プロキシサーバー越えができるようにした。
Socket.ioのプロキシー越えは、nginxでできるが、実装はしていない。nginx(発音は「Engine-X」)は、ロシアで開発された軽量かつ高速なWebサーバー(フリーかつオープンソース)で、バイナリーのサイズがたった約600キロバイトしかないそうである。 HTTP、SMTP、POP3、IMAPのリバース・プロキシーの機能も持つ(wikipedia等より)。
4.2 リソース
Websocket版チャットプログラム(HTML、node.js)
Socket.io版チャットプログラム(HTML、node.js)
4.3 デモ
4.4 Websocketでも音楽配信
“WebSocketのバイナリメッセージを試したら、ウェブの未来が垣間見えた”は、リアルタイム通信、バイナリー送信について言及し、未来のWebのあり方を説いていて、是非一読を(内容が難しいと思った人は、文頭と文末だけもで)。
このサイトでは、Websocketによるバイナリー配信の実例として、“Web Audio API(Chrome Only)”を用いて、音楽の配信を行っているこのプログラムは大変秀逸で、大変勉強になった。このプログラムに対して、express3.0対応、受信データのバッファリングを設けジッタへの対応(ジッタの解消までには至らなかった)、PlayList機能の追加を行った。
音楽視聴の仕組みは、クライアントのプレイヤー再生音をWeb Audio APIが逐次サンプリングし、このデータをwebsocketでサーバーを経由して受信クライアントに送る。受信クライアントは、Web Audio APIを通して、受信したデータをプレイヤーに渡し、音源再生ができる。プレイヤーからサンプリングを行うため、ステレオ音源でもモノラル音源でも4Mbps弱のデータ転送を伴う。
4.5 音楽視聴デモ
オリジナルは3000ポートのみで動作するものであったが、httpの8003ポートを利用するものにアレンジ。さらに拡張したプログラムはhttpの8011ポートを利用したものアレンジ。
元に近いバージョン※プロキシー経由できない、Chromeだけ
アレンジ版(発信者、視聴者)※プロキシー経由できない、Chromeだけ
記 大坂哲司