#WebSocket

WebSocket は、多くの高度な機能に必要なネットワーク通信プロトコルです。

WebSocket を初めて使用する人は誰でも同じ質問をするでしょう。HTTP プロトコルはすでにあるのに、なぜ別のプロトコルが必要なのでしょうか?それはどのようなメリットをもたらしますか?

答えは簡単です。HTTP プロトコルには、クライアントによってのみ通信を開始できるという欠陥があるからです。たとえば、今日の天気を知りたい場合、クライアントはサーバーにリクエストを行うことしかできず、サーバーはクエリ結果を返します。 HTTP プロトコルでは、サーバーがクライアントに情報をアクティブにプッシュすることはできません。 HTTP プロトコルの一方向リクエスト機能は、サーバーのステータスが継続的に変化しているかどうかをクライアントが知るのを非常に困難にする運命にあります。使用できるのは「ポーリング」のみです。サーバーに新しい情報があるかどうかを確認するために、時々クエリが発行されます。最も典型的なシナリオはチャット ルームです。

ポーリングは非効率的であり、リソースを浪費します (接続し続ける必要があるか、HTTP 接続が常に開いているため)。そこでエンジニアたちは、もっと良い方法はないかと考えてきました。これが WebSocket が発明された方法です。

導入

WebSocket プロトコルは 2008 年に誕生し、2011 年に国際標準になりました。すべてのブラウザがすでにサポートしています。

その最大の特徴は、サーバーがクライアントにアクティブに情報をプッシュできること、そしてクライアントもサーバーにアクティブに情報を送信できることです。これは、真の双方向の対等な対話であり、サーバー プッシュ テクノロジーの一種です。 WebSocket により、サーバーとクライアント間の全二重通信が可能になります。たとえば、HTTP プロトコルは電子メールの送信に似ており、送信後は相手の応答を待つ必要があります。WebSocket は電話をかけるのと似ており、サーバーとクライアントは同時にデータを相互に送信できます。そしてそれらの間には継続的に開いているデータチャネルがあります。

その他の機能は次のとおりです。

(1) TCP プロトコルに基づいて構築されているため、サーバー側の実装は比較的簡単です。

(2) HTTPプロトコルとの互換性が良好です。デフォルトのポートも 80 と 443 で、ハンドシェイク フェーズでは HTTP プロトコルが使用されるため、ハンドシェイク中にブロックされにくく、さまざまな HTTP プロキシ サーバーを通過できます。

(3) データ形式は比較的軽量で、パフォーマンスのオーバーヘッドが低く、通信が効率的です。

(4) テキストまたはバイナリデータを送信できます。

(5) 同一オリジンの制限がなく、クライアントはどのサーバーとも通信でき、Ajax を完全に置き換えることができます。

(6) プロトコル識別子は「ws」(暗号化されている場合は、HTTPS プロトコルに対応する「wss」)、サーバーアドレスは URL です。

ws://example.com:80/some/path

WebSocket ハンドシェイク

ブラウザによって発行される WebSocket ハンドシェイク リクエストは次のようになります。

GET/HTTP/1.1
接続: アップグレード
アップグレード: WebSocket
ホスト: example.com
出身地: null
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-バージョン: 13

上記のヘッダー情報のうち、HTTP ヘッダーの 1 つが「Upgrade」です。 HTTP1.1プロトコルでは、「アップグレード」フィールドが、通信プロトコルを「HTTP/1.1」からこのフィールドで指定されたプロトコルに変更することを示すと規定されている。 「Connection」フィールドは、可能であれば WebSocket プロトコルにアップグレードするようにブラウザがサーバーに通知することを示します。 「Origin」フィールドは、リクエストの発行元のドメイン名を提供し、それが許可された範囲内にあるかどうかをサーバーが検証するために使用されます(サーバーはそれを検証する必要はありません)。 「Sec-WebSocket-Key」はハンドシェイク プロトコルに使用されるキーで、Base64 でエンコードされた 16 バイトのランダムな文字列です。

サーバーの WebSocket 応答は次のとおりです。

HTTP/1.1 101 スイッチングプロトコル
接続: アップグレード
アップグレード: WebSocket
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Origin: null
Sec-WebSocket-Location: ws://example.com/

上記のコードでは、サーバーは「Connection」フィールドも使用して、プロトコルを変更する必要があることをブラウザーに通知します。 Sec-WebSocket-Accept フィールドは、サーバーがブラウザによって提供される Sec-WebSocket-Key 文字列の後に RFC6456 標準の「258EAFA5」を追加します。 -E914-47DA-95CA-C5AB0DC85B11" という文字列を入力し、SHA-1 ハッシュ値を取得します。ブラウザはこの値を検証して、実際に WebSocket リクエストに応答したターゲット サーバーであることを証明します。 「Sec-WebSocket-Location」フィールドは、通信用の WebSocket URL を表します。

ハンドシェイクが完了すると、WebSocket プロトコルが TCP プロトコルの上に動作し、データの送信を開始します。

クライアントの簡単な例

WebSocket の使い方は非常に簡単です。

以下に Web スクリプトの例を示します。基本的には一目で理解できます。

var ws = 新しい WebSocket('wss://echo.websocket.org');

ws.onopen = function(evt) {
  console.log('接続がオープンしました ...');
  ws.send('こんにちは WebSocket!');
};

ws.onmessage = function(evt) {
  console.log('受信したメッセージ: ' + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log('接続が閉じられました。');
};

クライアント API

ブラウザによる WebSocket プロトコルの処理は、次の 3 つにすぎません。

  • 接続の確立と切断
  • データの送信とデータの受信
  • エラーの処理

コンストラクター WebSocket

WebSocket オブジェクトは、新しい WebSocket インスタンスを作成するために使用されるコンストラクターとして機能します。

var ws = 新しい WebSocket('ws://localhost:8080');

上記のステートメントを実行すると、クライアントはサーバーに接続します。

webSocket.readyState

readyState プロパティはインスタンス オブジェクトの現在の状態を返します。4 つのタイプがあります。

  • CONNECTING: 値は 0 で、接続中であることを示します。
  • OPEN: 値は 1 で、接続が成功し、通信が可能であることを示します。
  • CLOSING: 値 2 は、接続が閉じていることを示します。
  • CLOSED: 値 3 は、接続が閉じられたか、接続のオープンに失敗したことを示します。

ここに例を示します。

スイッチ (ws.readyState) {
  WebSocket.CONNECTING の場合:
    //何かをする
    壊す;
  WebSocket.OPENの場合:
    //何かをする
    壊す;
  ケース WebSocket.CLOSING:
    //何かをする
    壊す;
  WebSocket.CLOSED の場合:
    //何かをする
    壊す;
  デフォルト:
    // これは決して起こりません
    壊す;
}

webSocket.onopen

インスタンス オブジェクトの onopen 属性は、接続が成功した後のコールバック関数を指定するために使用されます。

ws.onopen = function () {
  ws.send('こんにちはサーバー!');
}

複数のコールバック関数を指定したい場合は、addEventListener メソッドを使用できます。

ws.addEventListener('open', 関数 (イベント) {
  ws.send('こんにちはサーバー!');
});

webSocket.onclose

インスタンス オブジェクトの onclose 属性は、接続が閉じられた後のコールバック関数を指定するために使用されます。

ws.onclose = 関数(イベント) {
  var コード = イベント.コード;
  var 理由 = イベント.理由;
  var wasClean = イベント.wasClean;
  // クローズイベントをハンドルします
};

ws.addEventListener("close", function(event) {
  var コード = イベント.コード;
  var 理由 = イベント.理由;
  var wasClean = イベント.wasClean;
  // クローズイベントをハンドルします
});

webSocket.onmessage

インスタンス オブジェクトの onmessage 属性は、サーバー データ受信後のコールバック関数を指定するために使用されます。

ws.onmessage = 関数(イベント) {
  var データ = イベント.データ;
  //データを処理する
};

ws.addEventListener("メッセージ", function(event) {
  var データ = イベント.データ;
  //データを処理する
});

サーバー データはテキスト データまたはバイナリ データ (「blob」オブジェクトまたは「Arraybuffer」オブジェクト) である場合があることに注意してください。

ws.onmessage = 関数(イベント){
  if(イベントのタイプ.データ === 文字列) {
    console.log("受信データ文字列");
  }

  if(event.data インスタンスの ArrayBuffer){
    var バッファ = イベント.データ;
    console.log("受信した配列バッファ");
  }
}

受信したデータ型を動的に決定するだけでなく、binaryType 属性を使用して受信したバイナリ データ型を明示的に指定することもできます。

// 受信したのは BLOB データです
ws.binaryType = "ブロブ";
ws.onmessage = function(e) {
  console.log(e.data.size);
};

// 受信したのは ArrayBuffer データです
ws.binaryType = "配列バッファ";
ws.onmessage = function(e) {
  console.log(e.data.byteLength);
};

webSocket.send()

インスタンス オブジェクトの send() メソッドは、サーバーにデータを送信するために使用されます。

テキストの送信例。

ws.send('あなたのメッセージ');

Blob オブジェクトの送信例。

var ファイル = ドキュメント
  .querySelector('input[type="file"]')
  .files[0];
ws.send(ファイル);

ArrayBuffer オブジェクトの送信例。

// キャンバスの ImageData を ArrayBuffer として送信します
var img = Canvas_context.getImageData(0, 0, 400, 320);
var binary = 新しい Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  バイナリ[i] = img.data[i];
}
ws.send(binary.buffer);

webSocket.bufferedAmount

インスタンス オブジェクトの bufferedAmount プロパティは、送信されていないバイナリ データのバイト数を示します。送信が完了したかどうかを判断するために使用できます。

var データ = 新しい ArrayBuffer(10000000);
ソケット.send(データ);

if (socket.bufferedAmount === 0) {
  //送信完了
} それ以外 {
  // 送信はまだ終わっていません
}

webSocket.onerror

インスタンス オブジェクトの onerror 属性は、エラーが報告されたときのコールバック関数を指定するために使用されます。

ソケット.onerror = 関数(イベント) {
  // エラーイベントを処理します
};

ソケット.addEventListener("エラー", function(event) {
  //エラーイベントを処理する
});

WebSocket サーバー

WebSocket プロトコルにはサーバーのサポートが必要です。さまざまなサーバーの実装については、Wikipedia の リスト を参照してください。

一般的に使用される Node 実装は 3 つあります。

具体的な使用方法については、ドキュメントを参照してください。このチュートリアルでは詳しく説明しません。

参考リンク


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0