WebSocketによる共有
そしてこのサンプルの一番のポイントである、Socket.IOを使用したユーザ体験のリアルタイムな共有です。
このサンプルではマウスポインタが移動した」「黒板消しで消した」「線を書いた」と言った操作をJSON形式でサーバに送信しています。それを受け取ったサーバは、それを送信元以外のクライアントに対してブロードキャストします。各クライアントはそれを受け取ってその操作を黒板に対して実行する、という実装を行っています。
実際のコードで見てみましょう。図で言うと(1)の処理を行うコードです。
(1)クライアントからサーバへのデータ送信をSocket.IOで行う
例えばマウスポインタが移動した際、以下のようなコードでsendCommand()というメソッドを呼び出しています。
mouseMove: function(param, share) { if (!share) { return; } // サーバへのデータ送信 sendCommand({ type : "mouseMove", param : param }); }
sendCommand()メソッドは、Socket.IOのAPIを使用しています。クライアント側におけるSocket.IOは、io.connect(URL)によって生成される「ソケット」というオブジェクトを使用します。
var socket = io.connect(location.protocol + '//' + location.host + '/chalkboard');
ソケットが持つ「emit()」というメソッドを用いて、サーバに対してJSONオブジェクトを送信することができます。第一引数はイベント名で、イベントの種別を識別するために汎用的に利用できます。
sendCommand = function(command) { socket.emit('command', command); };
(2)Node.jsとSocket.IOを使用したサーバプログラム
次に掲載するコードは、サーバサイドで(2)の処理を実行する箇所です。Node.jsを利用しているため、サーバサイドのコードもJavaScriptで記述しています。
サーバは、クライアントから送られてきたコマンドを受け取って、送信元以外にブロードキャストします。サーバプログラムの主要部分を以下に掲載します。
const COMMANDS_MAX = 2000; var commands = []; // クライアントからの操作ログを配列に保持する function storeCommand(command) { if (commands.length === COMMANDS_MAX) { // 古い操作ログは削除する commands.shift(); } commands.push(command); } // Socket.IOを使用し、/chalkboardというURLを待ち受ける var sockets = io.of('/chalkboard').on('connection', function(socket) { // 累積したコマンドをクライアントに向けて送る socket.emit('init', commands); // クライアントからコマンドを受け取る socket.on('command', function(command) { // コマンドにセッションIDを紐付ける command.sessionId = socket.id; // mouseMoveイベントは保存しない if (command.type !== 'mouseMove') { storeCommand(command); } // 送信元以外のクライアントにブロードキャスト socket.broadcast.emit('command', command); }); // 接続が切断されたら、全クライアントに通知 socket.on('disconnect', function() { socket.broadcast.emit('leave', socket.id); }); });
中でもポイントとなる部分を抜粋します。なんと、クライアントから受け取ったコマンドを送信元以外のクライアントにブロードキャストする処理を、一行で記述できています。
Socket.IOのAPIが非常に使いやすいことがお分かりいただけるのではないでしょうか。
// クライアントからコマンドを受け取る socket.on('command', function(command) { ... // 送信元以外のクライアントにブロードキャスト socket.broadcast.emit('command', command); });