socket.ioの習作解説その参
socket.ioの具体的なサービスコードは、例えるならばトランシーバーみたいな考え方です。自分が通話するときはボタン押してしゃべって、あとは手を離しておけば聞こえるという。
//サーバ側 chatroom.on('connection', function(socket) { heartbeat(); socket.on('upstream', function(data) { chatroom.emit('downstream', data); heartbeat(); }); });
名前空間「/chatroom」で立ち上げたこいつはWebSocketのI/Oを握ってるEventEmitterなので、それぞれ送受信のハンドラを書いていきます。まずconnectionイベントのハンドラ。ここに設定するコールバックはfunction(socket)とサーバ - ブラウザの個々の接続が渡されてきますので、もらったsocketに受信ハンドラを設定します。「upstream」とあるのはこのサンプルで定義した独自イベント名です。ブラウザからの上りメッセージなので「upstream」としましたが、これはサーバ側とブラウザ側でそろえればどんな名前でもいい。こちらで設定するコールバックはfunction(data)と引数に具体的なデータが入ってきますので、これを用いてサービスのロジックを作ります。サンプルでは個別ブラウザから上がってきたこのdataを名前空間に接続している全ブラウザにプッシュ配信しています。名前空間たるchatroomのemitメソッドで。こちらも第一引数には独自イベント名を定義しました。サーバからの下りメッセージなので「downstream」としています。もちろんこれもサーバ側とブラウザ側でそろえればどんな名前でもいい!
<!--ブラウザ側--> chatroom.on('downstream', function (data) { var data$ = $('<div>').text(new Date() + ': ' + data); $('#messageArea').append(data$); }); $('#sendBtn').click(function() { chatroom.emit('upstream', $('#textBox').val()); $('#textBox').val(''); });
ブラウザ側のハンドラでは、サーバからの下りメッセージを捉えるべく「downstream」を押さえます。サーバ側とまったく同じ記述方法で、dataを取り扱うコード。ここではjQueryを使ってメッセージに受信日付をつけてdivタグに囲って表示行をappendしています。
ブラウザからの上りメッセージは、テキストボックスとボタンを配置したうえ、ボタンのclickハンドラに送信コードを仕込みました。こちらもサーバ側とおなじ見かけのコードで、名前空間たるchatroomのemitメソッドで。「upstream」イベント名でサーバ側とそろえて送信しています。
送信ロジックはサーバ側とブラウザ側でおんなじように書けますが、よく考えるとサーバとクライアントで立場違いますので、ちょっと違いますね。サーバ側は一つではなく多数のブラウザと同時に接続しますが、ブラウザ側から見るとサーバは一つです。よって同じchatroom.emit()でもサーバ側は全ブラウザ向け配信になるし、クライアント側はサーバ一つへのメッセージアップロードです。サーバ側を全ブラウザ向け配信ではなく、個別ブラウザへの狙い撃ちメッセージにするには以下。
//サーバ側 socket.on('upstream', function(data) { socket.emit('downstream', data); // chatroom -> socketへの変更 heartbeat(); });
chatroom.emit()ではなく、socket.emit()。このsocketはconnectionイベントに設定するコールバックの引数としてもらうsocketのことです。このsocketはクロージャで参照されているので、WebSocketの接続が維持されている間はいつでも使えます。
//サーバ側 var timeoutID = 0; function heartbeat() { clearTimeout(timeoutID); timeoutID = setTimeout(function() { chatroom.emit('downstream', '沈黙しないで!'); heartbeat(); }, 10000); }
この関数はおまけ。10秒後にタイマーをセットして上りメッセージが途絶えると「沈黙しないで!」と書き込みを促すようにしました。Java的脳だと大丈夫かこれ?と思っちゃいますよね。でもNode.jsは単一ループだから絶対的に後がちルール。非同期実行なのにコンカレントな配慮はまったく必要なし。だから(たぶん)これでイイ。