Socket.IO開発時に役立つツール4選とroom、namespaceライブラリの使い方:Socket.IOで始めるWebSocket超入門(終)(1/3 ページ)
本連載では、WebSocketを扱えるNode.jsのライブラリ「Socket.IO」の使い方について解説します。今回は、チャットアプリ開発を進めながら、「room」「namespace」ライブラリの使い方について説明し、最後に開発時に役立つツールを4つ紹介します。
本連載「Socket.IOで始めるWebSocket超入門」では、WebSocketを扱うことができるNode.jsのライブラリ「Socket.IO」を使って、サンプルアプリケーションを構築していきます。
具体的には、チャットを題材とし、送受信されるメッセージ内容が即時反映されるリアルタイムかつ双方向なWebアプリケーションの構築を目標とします。さらに構築の中で、Socket.IOの各種ライブラリの使い方について解説することで、Socket.IOを使ったWebSocketの実践方法を体系的に学びます。
前回の「チャットアプリ開発に見る、Socket.IOの基本ライブラリの使い方」では、実際にチャットアプリ開発をしながら、Socket.IO基本ライブラリの使い方を確認しました。今回は、さらにチャットアプリ開発を進めながら、「room」「namespace」ライブラリの使い方について説明します。
以降は、前回のチャットアプリ開発までが完了していることが前提です。もし、まだチャットアプリ開発まで終わっていない方は、前々回、前回記事を参考にしてみてください。
「room」「namespace」とは
Socket.IOでは、データの送受信だけではなく、「room」「namespace」という2つのライブラリを提供しています。
roomは、双方向・リアルタイムデータ送受信を任意の範囲で行うための仕組みです。roomを使用すると、文字通り、その部屋に所属するクライアント間のみでデータをやりとりすることが可能です。
namespaceは、Socket.IOの実装を機能単位で分割するための仕組みです。例えば、現在のチャットアプリに外部API連携機能や、お知らせ機能を追加する際に、namespaceを使用すると簡単に実装することが可能です。
それでは、2つのライブラリについて、順に実装しながら説明します。
roomを使ったチャットルームの実装
前回記事時点でのチャットアプリには、チャットルームがありません。そこで、チャットルーム機能をroomを使用して実装します。今回は、「部屋01」「部屋02」という2つの部屋を用意します。実現したいことのイメージ図を以下に記載します。
それでは、実際に実装してみましょう。
クライアント側の実装
まずは、クライアントサイドです。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>websocket-chat</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- C01. Socket.IOクライアントライブラリの読込み --> <script type="text/javascript" src="/socket.io/socket.io.js"></script> </head> <body> <div class="container"> <h1>WebSocket-Chat</h1> <form class="form-inline"> <div class="form-group"> <label class="roomLabel" for="rooms">部屋:</label> <select class="form-control" id="rooms"> <option value="room01">部屋01</option> <option value="room02">部屋02</option> </select> <label class="nameLabel" for="msgForm">名前:</label> <input type="text" class="form-control" id="msgForm"> </div> <button type="submit" class="btn btn-primary" id="sendButton">入室</button> </form> <div id="chatLogs"></div> </div> <script type="text/javascript"> var socket = io.connect(); // C02. ソケットへの接続 var isEnter = false; var name = ''; // C04. server_to_clientイベント・データを受信する socket.on("server_to_client", function(data){appendMsg(data.value)}); function appendMsg(text) { $("#chatLogs").append("<div>" + text + "</div>"); } $("form").submit(function(e) { var message = $("#msgForm").val(); var selectRoom = $("#rooms").val(); $("#msgForm").val(''); if (isEnter) { message = "[" + name + "]: " + message; // C03. client_to_serverイベント・データを送信する socket.emit("client_to_server", {value : message}); } else { name = message; var entryMessage = name + "さんが入室しました。"; socket.emit("client_to_server_join", {value : selectRoom}); // C05. client_to_server_broadcastイベント・データを送信する socket.emit("client_to_server_broadcast", {value : entryMessage}); // C06. client_to_server_personalイベント・データを送信する socket.emit("client_to_server_personal", {value : name}); changeLabel(); } e.preventDefault(); }); function changeLabel() { $(".nameLabel").text("メッセージ:"); $("#rooms").prop("disabled", true); $("button").text("送信"); isEnter = true; } </script> </body> </html>
クライアントサイドでは、チャット部屋のセレクトボックスと、選択された部屋名をサーバサイドに送信するclient_to_server_joinイベントを追加しています。
サーバ側の実装
続いてサーバサイドです。
// S01. 必要なモジュールを読み込む var http = require('http'); var socketio = require('socket.io'); var fs = require('fs'); // S02. HTTPサーバを生成する var server = http.createServer(function(req, res) { res.writeHead(200, {'Content-Type' : 'text/html'}); res.end(fs.readFileSync(__dirname + '/index.html', 'utf-8')); }).listen(3000); // ポート競合の場合は値を変更 // S03. HTTPサーバにソケットをひも付ける(WebSocket有効化) var io = socketio.listen(server); // S04. connectionイベントを受信する io.sockets.on('connection', function(socket) { var room = ''; var name = ''; // roomへの入室は、「socket.join(room名)」 socket.on('client_to_server_join', function(data) { room = data.value; socket.join(room); }); // S05. client_to_serverイベント・データを受信する socket.on('client_to_server', function(data) { // S06. server_to_clientイベント・データを送信する io.to(room).emit('server_to_client', {value : data.value}); }); // S07. client_to_server_broadcastイベント・データを受信し、送信元以外に送信する socket.on('client_to_server_broadcast', function(data) { socket.broadcast.to(room).emit('server_to_client', {value : data.value}); }); // S08. client_to_server_personalイベント・データを受信し、送信元のみに送信する socket.on('client_to_server_personal', function(data) { var id = socket.id; name = data.value; var personalMessage = "あなたは、" + name + "さんとして入室しました。" io.to(id).emit('server_to_client', {value : personalMessage}); }); // S09. dicconnectイベントを受信し、退出メッセージを送信する socket.on('disconnect', function() { if (name == '') { console.log("未入室のまま、どこかへ去っていきました。"); } else { var endMessage = name + "さんが退出しました。" io.to(room).emit('server_to_client', {value : endMessage}); } }); });
サーバサイドでは、client_to_server_joinイベント受信処理を追加しています。アクセスしたクライアントを特定のroomに入室させるには、「socket.join(room名)」を使用します。
また、emit(送信)処理を以下のように変更しています。
変更前 | 変更後 | |
---|---|---|
io.sockets.emit(全クライアント送信) | io.to(room).emit | |
socket.broadcast.emit(ブロードキャスト送信) | socket.broadcast.to(room).emit |
データ送信を特定のroomに限定するには、「to(room名)」を使用します。これにより、全クライアント送信・ブロードキャスト送信の範囲は指定したroomのみになります。
ちなみに、入室したroomから退室したい場合は、「socket.leave(room名)」を使用します。ただし、Socket.IOでは、disconnectイベントが発生すると自動的にそのクライアントをroomから退出させます。入室したチャットルームを切り替えるなど、disconnectイベント以外でroom退室処理が必要な場合のみ使用すればいいでしょう。
動作確認
コードの変更・保存が完了したら、アプリケーションの動作を確認します。4つのブラウザウィンドウでアプリケーションを開いてください。その後、部屋01、部屋02にそれぞれ2クライアントずつ入室します。
部屋01、部屋02のクライアントでそれぞれメッセージを送信します。
メッセージが、全クライアントではなく、部屋01、部屋02の範囲内でのみ共有されたことが確認できたと思います。このように、roomを使用すると、データの送信対象を任意にグループ化することができます。
roomへの入室:socket.join(room名) / roomから退室:socket.leave(room名)
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- WebSocketが一番速いアプリケーションサーバはどれだ?
双方向通信を実現するHTML5関連技術WebSocketを実装した3つのアプリケーションサーバの実装の違い・性能などを徹底検証する。 - Play2+nginx/Akka/WebSocketで高速双方向通信
Play framework 2.xを既存のWebサーバーと連携させる方法、並列処理や双方向通信を行う方法を紹介します。 - Socket.IOでセンサー&MongoDB〜AngularJSアプリ間の通信を行う
家電〜Webアプリ間の双方向通信をSocket.IOで行うアプリについて、サーバー側のArduino連携やMongoDBへのデータ保存などと、クライアント側のAngularJSに分けて動作を解説します。