作成201393

 編集20131018

リアルタイム双方向通信について

 

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)socketopen(2)相手方からのコネクションを受け、コネクションをopen、その後、(3)(4)メッセージを送り、送られたメッセージを受け取り、メッセージに対応した処理を行う、(5)コネクションの終了、と言った手順で、リアルタイム双方向通信が実現できる。

 Websocketの応用例として、NHKが推進しているHybridcastがある。Hybridcastの受像機では、BMLブラウザーとHTML5ブラウザーが同居し、受像機とスマートデバイス(セカンドスクリーン)がWebsocketでつながるらしい。番組を見ながら、番組連動の情報がセカンドスクリーンにPUSHされる、そんな日がそこまで来ている。

 

2.2 WebsocketHTML)のコードサンプル

<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 Websocketnode.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.ioWebsocketのバイナリーデータの取り扱いなどを取り込み、Websocketを凌駕しようとしているが、もう少し時間がかかりそうである(Socket.io V1.0以降)。

 

3.1 Socket.ioによる通信

 Socket.ioWebsocketと同様の手順で、リアルタイム双方向通信ができる。上記Websocketのコードサンプルと比べ、差異は少ない。

 

3.2 Socket.ioHTML)のコードサンプル

<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.ionode.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.WebsocketSocket.ioの違い

Websocketは、W3CHTML5で規格としてまとめているリアルタイム双方向通信技術であり、作動条件は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.)。

一般的なプログラマーから見て、WebsocketSocket.ioの違いはほとんどないが、現時点では、Websocketはバイナリーデータが扱える、Socket.ioは使い易い、など若干の違いがある。

両者の選択については、利用条件、データ転送効率などのベンチマーク評価、プロキシーサーバーが越えられるかなどを含め、調査する必要がある。

 

 リアルタイム双方向通信のデモと言えばチャットでしょ。WebsocketSocket.ioそれぞれを用いてチャットプログラムを作成した。

 今回作成したチャットプログラムは、チャットメッセージをMongoDBに書き込み、Websocket Serverの接続ユーザー同士、Socket.io Serverの接続ユーザー同士でチャットを楽しむことができる。当然であるが、プロトコルが異なるため、WebsocketSocket.ioが混在した通信はできない。両サーバーともHttpサーバー機能があるため、MongoDBの参照は共にできる。

 Websocketでは、node-http-proxy.jsを用いたリバース・プロキシーを設け、プロキシサーバー越えができるようにした。

Socket.ioのプロキシー越えは、nginxでできるが、実装はしていない。nginx(発音は「Engine-X」)は、ロシアで開発された軽量かつ高速なWebサーバー(フリーかつオープンソース)で、バイナリーのサイズがたった約600キロバイトしかないそうである。 HTTPSMTPPOP3IMAPのリバース・プロキシーの機能も持つ(wikipedia等より)。

  

 

4.2 リソース

              Websocket版チャットプログラム(HTMLnode.js

              Socket.io版チャットプログラム(HTMLnode.js

 

4.3 デモ

Websocket版(チャットDB参照

Socket.io版(チャットDB参照

 

4.4 Websocketでも音楽配信

 WebSocketのバイナリメッセージを試したら、ウェブの未来が垣間見えた”は、リアルタイム通信、バイナリー送信について言及し、未来のWebのあり方を説いていて、是非一読を(内容が難しいと思った人は、文頭と文末だけもで)。

 このサイトでは、Websocketによるバイナリー配信の実例として、“Web Audio APIChrome Only)”を用いて、音楽の配信を行っているこのプログラムは大変秀逸で、大変勉強になった。このプログラムに対して、express3.0対応、受信データのバッファリングを設けジッタへの対応(ジッタの解消までには至らなかった)、PlayList機能の追加を行った。

 音楽視聴の仕組みは、クライアントのプレイヤー再生音をWeb Audio APIが逐次サンプリングし、このデータをwebsocketでサーバーを経由して受信クライアントに送る。受信クライアントは、Web Audio APIを通して、受信したデータをプレイヤーに渡し、音源再生ができる。プレイヤーからサンプリングを行うため、ステレオ音源でもモノラル音源でも4Mbps弱のデータ転送を伴う。

4.5 音楽視聴デモ

 オリジナルは3000ポートのみで動作するものであったが、http8003ポートを利用するものにアレンジ。さらに拡張したプログラムはhttp8011ポートを利用したものアレンジ。

  元に近いバージョン※プロキシー経由できない、Chromeだけ

  アレンジ版(発信者視聴者※プロキシー経由できない、Chromeだけ

記 大坂哲司