WebSocket入門 〜チャットアプリも作れるリアルタイム双方向通信を学ぼう〜
はじめに
リアルタイムの双方向の通信技術であるWebSocketについて説明します。内容は次の通りです。
WebSocketとは
WebSocketとは、Webにおいて双方向通信を低コストで行うためのプロトコルです。WebSocketの必要性について考える前に、HTTPプロトコルについて復習しましょう。
HTTPプロトコルでは、まずクライアント側からサーバー側へリクエストを送り、そのリクエストに応じてサーバー側がレスポンスを返します。この方法の問題点は、リクエストはクライアント側からしか送ることができないことです。
例えば、天気情報を提供するサーバーへ1分間隔でリクエストを送れば最新の天気情報のレスポンスを得ることができます。天気は1分以内の変化はそれほど激しくないためこれで十分ですが、株の相場情報のようにリアルタイム性を求める場合はどうでしょうか。
高頻度で変化する相場情報を提供するサーバーへ1分間隔でリクエストを送りレスポンスを受け取っていては、途中の値動きを見逃す可能性があります。さらにリクエストの頻度を上げることもできますが、サーバー側の負荷が大きくなります。このような、相場やオンライン対戦ゲームやビデオ会議チャットアプリといったリアルタイム性が求められる場面では、変化があるたびにサーバー側からクライアント側へデータを送れると便利ですね。そこで生まれたのがWebSocketプロトコルです。
WebSocketとHTTP通信のデモ
HTTP通信とWebSocket通信の違いを具体的なデモを通して比較してみましょう。ここでは、仮想通貨の取引所であるGMOコインが提供するAPIを用います。APIドキュメントをご覧ください。
HTTP通信のデモ
まずはHTTP通信から見ていきましょう。先ほどのドキュメントのPublic API内にある「最新レート」を見ましょう。右側でNode.jsのサンプルコードを見ることができます。
gmo-http.jsvar request = require('request'); var endPoint = 'https://api.coin.z.com/public'; var path = '/v1/ticker?symbol=BTC'; request(endPoint + path, function (err, response, payload) { console.log(JSON.stringify(JSON.parse(payload), null, 2)); });
ここでは、最初にrequestモジュールを使用しています。そのためnpm install
コマンドでrequestモジュールをインストールする必要があります。
npm install request
次に、APIのエンドポイントとパスを変数に代入します。最後にrequest
を呼び出し、コールバック関数のpayload
引数で結果を受け取ります。
それでは実行してみましょう。ファイルをgmo-http.js
という名前で保存しnode gmo-http.js
とターミナルで実行してみます。取引所のサーバーへリクエストを送信することで、現在のレートが返されます。
HTTP通信では1回リクエストを送ると1回結果が返ってくることがわかります。
WebSocket通信のデモ
同様に、WebSocket通信を見ていきましょう。APIドキュメントのPublic WebSocket API内にある「最新レート」を見ましょう。右側でNode.jsのサンプルコードを見ることができます。
gmo-websocket.jsconst WebSocket = require("ws"); const ws = new WebSocket("wss://api.coin.z.com/ws/public/v1"); ws.on("open", () => { const message = JSON.stringify( { "command": "subscribe", "channel": "ticker", "symbol": "BTC" }); ws.send(message); }); ws.on("message", (data) => { console.log("WebSocket message: ", data); });
こちらでは、wsモジュールを使用しています。HTTP通信の時と同様にnpm install
コマンドを使用すれば良いですね。2行目では接続先のURLを引数に渡してインスタンス化しています。
サーバーと接続できたら、必要な情報をmessage
変数に格納します。これを取引所のサーバーへ送信します。
最後にサーバーからデータを受け取ったらコンソールへ表示します。ただし、このまま出力するとバッファデータしか表示されないため、data.toString()
として文字列に変換して出力すると良いでしょう。
それでは実行してみましょう。ファイルをgmo-websocket.js
という名前で保存しnode gmo-websocket.js
とターミナルで実行してみます。レートが変わるタイミングでサーバー側から最新レートが送られていることが確認できます。
WebSocket通信ではサーバー側からクライアント側へ繰り返しデータを送ることができるというのが分かります。
WebSocketで作るチャットアプリ
WebSocketを用いたグループチャットアプリの実装を考えてみましょう。実装全体ではなく通信に関わる部分を説明します。動作の様子は6分17秒あたりで解説しています。
クライアント側の実装
クライアント側ではSocket.IOというライブラリを用います。
まずは<script>
タグでライブラリをロードします。
<script src="/socket.io/socket.io.js"></script>
次のようにして、インスタンス化します。
const sockcet = io();
チャットの送信時の処理を見てみましょう。emit
メソッドで送信します。第1引数にはイベント名を、第2引数にはname
とmesage
を含む送信したいデータを指定します。イベント名は自由に指定できますが、サーバー側で受け取る処理を記述する際にイベント名を一致させる必要があります。
function postMsg(name, message) {
const data = {
name,
msg,
};
socket.emit("msgPost", data)
}
次に、サーバーから受信する際の処理を見てみましょう。on
メソッドの第1引数にイベント名を、第2引数にはデータを受け取るコールバック関数を指定します。このイベント名も、送信側のサーバー側で指定するものと一致している必要があります。
socket.on("msgGet", (data) => {
// 画面に表示する処理
})
サーバー側の実装
サーバー用のSocket.ioライブラリを読み込み、インスタンス化します。
import { Server } from 'socket.io';
const io = new Server(server);
新しいクライアントが接続した際、最初に発生するのがconnection
イベントです。コールバック関数が受け取るsocket
は個々のクライアントです。
io.on("connection", (socket) => {
// 各クライアントに対する処理
})
さて、各クライアントからデータが送られてくるので、socket.on
メソッドでイベントをリッスンします。ここでイベント名msgPost
は先ほどクライアント側で指定した名前と対応しています。送られてきたデータをコールバック関数のdata
引数で受け取ります。
最後にio.emit
メソッドによって全てのクライアントにメッセージを送信します。msgGet
というイベント名もクライアント側で指定したイベント名と一致するようにします。
socket.on("msgPost", (data) => {
const msgs = {
name: data.name,
msg: data.msg,
}
io.emit("msgGet", msgs);
})
これによって、特定のユーザーが送信したメッセージを他のユーザーも受信できるようになり、グループチャット機能が実現できます。
以上がsocket.ioを用いたチャットアプリの実装でした。
まとめ
今回は今回紹介した取引所のAPIやチャットアプリの実装をみながらWebSocketについて学習しました。
1回のリクエストに対し1回のレスポンスを行うHTTP通信に対し、WebSocketは一度接続すると繰り返しデータを送受信できました。リアルタイム性が求められる場面でぜひ使ってみてください。