ソケット(socket)とは?
アプリケーションがTCP/IPを使用して「IPアドレスとポート番号をセットにした通信」を行うための仮想的なプログラミングインタフェースです。OSI参照モデルで言えば、「セッション層」を扱うことができます。(一般的なHTTPなどはアプリケーション層に該当します。)
仕組み
通信相手に繋がる電話回線のようなもので、ソケットにデータを書き込んで相手にデータを送ったり、逆に相手から届いたデータをソケットから読み込んだりできます。
一つのコンピュータで扱えるソケット数には上限がある。
通常、コンピュータやサーバーでは同時に使用可能なソケット数に制限があります。TCPコネクションが1つ確立されるとソケットが1つ消費されるので、同時接続数がソケットの上限に達してしまうと、いずれかのTCPコネクションが切断されるまで新たなTCPコネクションを確立できなくなってしまいます。
Keep-aliveを使えばTCPコネクションを使い回せる。
WebブラウザはWebページにアクセスすると複数のTCPコネクションを確立しようとしますが、Keep-aliveという機能を使えば一つのTCPコネクションを使い回せます。
WebSocketとは?
2011年ごろから策定されたクライアントサーバ間の双方向のリアルタイム通信のために用意されたプロトコルです。
もともと、Ajaxや、CometなどHTTP通信ベースでリアルタイムにやりとりをする技術はあったのですが、元々リアルタイム通信をサポートしていないHTTP通信を無理やり使っている状態だったので、問題があったのです。
WebSocketを使うことで一つの接続で全てのデータを送受信するため普通のHTTP通信よりも効率的にデータを送受信することができます。
フロントエンド機能がよりリアルタイム通信が前提にありつつある昨今、WebSocketはより重要度を増しつつある技術になっています。
WebSocketの仕組み
まずは、HTTPで通信を確立します。一度コネクションが確立されたらHTTPからWebSocketへプロトコルを切り替えます。
具体的にはクライアントとサーバー間で「ws:」、「wss:」から始まるURIスキーム上でクライアント、サーバー間でデータのやり取りを行います。
イメージ図
注意点
クライアントもサーバーもどちらもWebSocketのプロトコルに対応している必要があります。(HTTPには対応しているサーバーは多いかと思いますが、WebScoketは比較的新しいプロトコルなので古いサーバーでは対応していない場合もあります。)
ブラウザであれば、最近のブラウザはWebSocketに対応していて当たり前ですが、サーバー側もWebSocketのプロトコルに対応している必要があります。
WebSocketに対応したサーバー
- Tomcat
- Jetty
- Node.js
ユースケース
- 複数人同時対戦ゲーム
- SNS
ライブラリ
Node.js
「Socket.IO」というライブラリが一番有名です。
Ruby on Rails
RailsでWebSocketを扱うためのフレームワークとしては「Action Cable」があります。
ライブラリの構造も従来のRailsに沿う形で実装されているのでRailsをそれなりに習熟された方ならばすぐに身に付けることができるでしょう。
実装方法
ブラウザに標準で実装されているWebSocket APIを使います。
初期化
フロント
1 |
const ws = new WebSocket('ws://サーバーのアドレス:ポート番号/'); |
onopenは、サーバーとの接続完了した時に呼ばれるイベントハンドラです。
1 |
ws.onopen = function (e) {}; |
バックエンド
websocket.ioモジュールに、WebサーバーをアタッチすることでWebサーバーと同じポート番号でブラウザからのデータを待ち受けるようになります。
1 2 3 4 |
var app = http.createServer(function(request, response){ // Webサーバ作成 // リクエストに応じてコンテンツを送信 }); var server = require('websocket.io').attach(app); // Webサーバと同じポート番号を使う |
送信
フロント
サーバーに文字列を送信したい場合に使います。
1 |
ws.send('文字列'); |
バックエンド
クライアントから接続されるとconnectionイベントが発行されます。
1 2 3 |
server.on('connection', function(socket) { socket.send("送信データ"); }); |
指定時間経過後に実行したい
setTimeoutを実行すると指定時間実行後に送信できたりします。
1 2 3 |
setTimeout(function() { socket.send("送信データ"); }, 1000); |
受信
フロント
onmessageは、サーバーからメッセージが返ってきたときに呼ばれるイベントハンドラです。
1 |
ws.onmessage = function(e){ console.log('サーバから返されたメッセージ:' + e.data); } |
バックエンド
クライアントから接続されるとconnectionイベントが発行されます。
1 2 3 4 5 |
server.on('connection', function(socket) { socket.on('message', function(data) { // 受信後の処理 }); }); |
切断
フロント
oncloseはサーバーが切断した場合に呼ぶイベントハンドラです。
1 |
ws.onclose = function(e){ console.log('切断'); } |
この記事へのコメントはありません。