JS WebSocketを使用して簡単なチャットを実装する方法

JS WebSocketを使用して簡単なチャットを実装する方法

ショートポーリング

ショートポーリングの実装アイデアは、ブラウザが数秒ごとにサーバーに HTTP リクエストを送信するというものです。リクエストを受信した後、サーバーはデータの更新の有無に関係なく直接応答します。サーバーが応答を完了すると、TCP 接続が閉じられます。コードの実装も最もシンプルで、XHR を使用して setInterval を通じてバックエンドに定期的にリクエストを送信し、最新のデータを取得します。

setInterval(関数() {
  フェッチ(url).then((res) => {
      // 成功コード
  })
}, 3000);

利点: 実装が簡単。

デメリット: データが短期間同期されなくなり、無効なリクエストが大量に発生し、セキュリティが低下し、リソースが無駄になります。

ロングポーリング

クライアントがリクエストを送信した後、サーバーはすぐにデータを返しません。サーバーはリクエスト接続をブロックし、サーバーのデータが更新されるか接続がタイムアウトするまですぐには切断しません。その後、クライアントは再度リクエストを送信して新しい接続を作成し、このプロセスを繰り返して最新のデータを取得します。一般的な効果は次のとおりです。

クライアントコードは次のとおりです。

関数async() {
    フェッチ(url).then((res) => {
        非同期();
        // 成功コード
    }).catch(() => {
        // タイムアウト async();
    })
}

利点: ポーリングに比べて最適化されており、適時性が向上します。

デメリット: 接続を中断したままにするとリソースが消費され、サーバーは有効なデータを返さず、プログラムはタイムアウトになります。

ウェブソケット

上記のショート ポーリングとロング ポーリングはどちらも、通信を実行する前にクライアントが Ajax リクエストを開始する必要があります。これらは HTTP プロトコルを使用し、サーバーはクライアントに情報を積極的にプッシュすることはできません。

スポーツイベント、チャットルーム、リアルタイムの位置情報などのシナリオでは、サーバーに接続するためにリクエストを継続的に送信する必要があるため、ポーリングは非常に非効率になり、リソースを浪費します。 WebSocket の登場により、サーバーがクライアントに情報を積極的に送信できるようになり、ブラウザはリアルタイムで通信できるようになりました。

WebSocket を使用したことがない人は、それが高度な技術だと考えるかもしれません。実は、WebSocket はよく使われる API が少なく、習得しやすいのが特長です。しかし、使い方を紹介する前に、まずは通信原理について見てみましょう。

コミュニケーションの原則

クライアントがサーバーとの WebSocket 接続を確立する場合、クライアントとサーバー間のハンドシェイク プロセス中に、クライアントはまず、WebSocket 接続を確立したいことをサーバーに通知する Upgrade 要求ヘッダーを含む HTTP 要求をサーバーに送信します。

クライアント側で WebSocket 接続を確立するのは非常に簡単です。

ws = new WebSocket('ws://localhost:9000'); を作成します。

HTTP や HTTPS と同様に、ws にもそれに対応する wss があり、安全な接続を確立するために使用されます。ローカルでは ws を例として取り上げました。このときのリクエスト ヘッダーは次のとおりです。

受け入れエンコーディング: gzip、deflate、br
受け入れ言語: zh-CN,zh;q=0.9
キャッシュ制御: キャッシュなし
: : : : : : : : : : : : : : :
ホスト: localhost:9000
オリジン: http://localhost:9000
プラグマ: キャッシュなし
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: 5fTJ1LTuh3RKjsJxydyifQ== // 応答ヘッダーに対応します Sec-WebSocket-Accept Sec-WebSocket-Version: 13 // websocket プロトコルのバージョンを示します Upgrade: websocket // websocket プロトコルへのアップグレードを示します User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/76.0.3809.132 Safari/537.36

応答ヘッダーは次のとおりです。

接続: アップグレード
Sec-WebSocket-Accept: ZUip34t+bCjhkvxxwhmdEOyx9hE=
アップグレード: websocket 

このとき、応答行 (General) でステータス コードが 101 Switching Protocols であることがわかり、接続が HTTP プロトコルから WebSocket 通信プロトコルに変換されたことがわかります。 変換が成功すると、接続は中断されずに全二重通信が確立され、その後のメッセージの送受信はこの接続チャネルを介して行われます。

リクエスト ヘッダーには Sec-WebSocket-Key フィールドがあり、これは対応するヘッダーの Sec-WebSocket-Accept に対応していることに注意してください。その機能は、悪意のある接続や無効な接続などの基本的な保護を提供することです。 Sec-WebSocket-Key は、クライアントによってランダムに生成される base64 エンコーディングです。サーバーはこのエンコーディングを使用し、固定アルゴリズムに従います。

GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // 固定文字列 accept = base64(sha1(key + GUID)); // key は Sec-WebSocket-Key 値、accept は Sec-WebSocket-Accept 値

GUID 文字列は RFC6455 で正式に定義された固定文字列であり、変更することはできません。

クライアントはサーバーから Sec-WebSocket-Accept 応答を受信すると、同じアルゴリズムを使用して、以前に生成した Sec-WebSocket-Key を計算します。一致した場合、ハンドシェイクは成功します。次に、HTTP 応答ステータス コードが 101 (プロトコルの切り替え) であるかどうかを判断します。そうであれば、接続を確立すれば完了です。

シンプルな1対1チャットの実装

次に、純粋なテキスト メッセージ タイプの 1 対 1 チャット (シングル チャット) 機能を実装します。これ以上は何もせずに、コードに直接進み、コメントに注目してみましょう。

クライアント:

関数 connectWebsocket() {
    ws = 新しい WebSocket ('ws://localhost:9000');
    // 接続成功を待機する ws.onopen = () => {
        console.log('サーバーWebSocketへの接続が成功しました');
        ws.send(JSON.stringify(msgData)); // send メソッドはメッセージをサーバーに送信します};

    // サーバーメッセージをリッスンする(メッセージを受信する)
    ws.onmessage = (メッセージ) => {
        message = JSON.parse(msg.data); とします。
        console.log('受信したメッセージ:', message)
        elUl.innerhtml += `<li>小秋: ${message.content}</li>`;
    };

    // 接続失敗をリッスンする ws.onerror = () => {
        console.log('接続に失敗しました。再接続しています...');
        Websocket() を接続します。
    };

    // 接続の終了を待機する ws.onclose = () => {
        console.log('接続が閉じられました');
    };
};
Websocket を接続します。

上記から、WebSocket インスタンスの API は理解しやすく、シンプルで使いやすいことがわかります。メッセージは send() メソッドを通じて送信でき、onmessage イベントを使用してメッセージを受信し、その後メッセージが処理されてページに表示されます。 onerror イベント (リスニング接続の失敗) がトリガーされた場合は、接続が中断されないように再接続を実行するのが最適です。

サーバー ノード: (ここでは ws ライブラリを使用)

定数パス = require('path');
定数 express = require('express');
express() は、定数です。
const server = require('http').Server(app);
WebSocket は 'ws' を必要とします。

wss = new WebSocket.Server({ server: server });

wss.on('接続', (ws) => { 

  // クライアントからのメッセージをリッスンします ws.on('message', (message) => {
    コンソールログ(wss.clients.size);
    msgData = JSON.parse(メッセージ) とします。   
    msgData.type === 'open'の場合{
      // 初期接続時にセッションを識別します ws.sessionId = `${msgData.fromUserId}-${msgData.toUserId}`;
    } それ以外 {
      sessionId = `${msgData.toUserId}-${msgData.fromUserId}` とします。
      wss.clients.forEach(クライアント => {
        (クライアントのセッションID === セッションID) の場合 {
          client.send(message); //対応するクライアント接続にメッセージを送信します}
      })  
    }
  })

  // 接続が閉じられました ws.on('close', () => {
    console.log('接続が閉じられました');  
  });
});

同様に、サーバーにも対応する送信メソッドと受信メソッドがあります。完全なサンプルコードはここにあります

この方法では、ブラウザとサーバーは問題なくメッセージを送信でき、その効果は次のようになります。

緑の矢印は送信されたメッセージを表し、赤の矢印は受信されたメッセージを表します。

ハートビートキープアライブ

実際の WebSocket の使用においては、長時間通信が行われない場合、接続が不安定になることがあります。このような不明な状況によって発生する接続中断は、クライアントとサーバー間の通信に影響を与えます。

このような状況を防ぐために、ハートビート キープアライブ方式があります。クライアントはハートビートのように一定の間隔で ping を送信して、サーバーにまだ生きていることを伝え、サーバーも pong を返して、クライアントにサーバーがまだ生きていることを伝えます。 Ping/pong は実際にはビジネスとは何の関係もない偽のメッセージであり、ハートビート パケットとも呼ばれます。

接続が成功した後、60 秒などの固定間隔でハートビート パケットを送信できます。

間隔を設定する(() => {
    ws.send('これはハートビートメッセージです');
}, 60000)

要約する

上記の紹介を通じて、WebSocket についてある程度理解できたはずです。実際、WebSocket は神秘的なものではありません。ここでは、記事の内容を簡単にまとめます。 WebSocket インスタンスが作成されると、リクエスト メッセージに特別なフィールド Upgrade を含む HTTP リクエストが送信されます。次に、接続が HTTP プロトコルから WebSocket プロトコルに変換され、クライアントとサーバーの間で全二重通信が確立されます。この通信接続を通じて、WebSocket の send メソッドと onmessage イベントを使用して情報を交換できます。

以上が、JS WebSocket を使って簡単なチャットを実装する方法の詳細です。WebSocket の詳細については、123WORDPRESS.COM の他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • js シンプルなネットワーク速度テスト方法の完全な例
  • Baidu と Google のスピードテストの JavaScript コードにアクセスする
  • JS 非同期コードユニットテストの魔法 Promise
  • ネイティブ js はフォームの定期的な検証を実装します (検証後にのみ送信)
  • JS での Reduce Fold Unfold の使用法の詳細な説明
  • エレガントなJSコードの書き方
  • Vue での weixin-js-sdk の一般的な使用方法の詳細な説明
  • JSホモロジー戦略とCSRFの詳細な説明
  • JavaScript でネットワーク速度をテストする方法

<<:  MySQL のロードバランサーとして nginx を使用する方法

>>:  MySQL ビューの原則と使用例の概要

推薦する

docker を使用して Redis マスター/スレーブを構築する方法

1. Docker環境を構築する1. Dockerfileを作成する Centos:latest か...

MySQLは現在の日付と時刻を取得する関数の例の詳細な説明

現在の日付 + 時刻 (日付 + 時刻) を取得する関数: now() mysql> now(...

CSS3 でクールなスライス画像カルーセル効果を実現

今日は、CSS を使用してクールな画像カルーセル コンポーネントを作成する方法を学びます。その原理は...

Linux ファイル記述子、ファイルポインタ、および inode の詳細

目次Linux - ファイル記述子、ファイルポインタ、インデックスノード1. Linux - ファイ...

Docker バインディング固定 IP/クロスホストコンテナ相互アクセス操作

序文これまでは、パイプワークで割り当てた静的 IP は一時的なものであり、再起動すると無効になってい...

Vue は、デスクトップから Web ページにファイルをドラッグするためのサンプル コードを実装します (画像/オーディオ/ビデオを表示できます)

効果使用する場合は、コードとスタイルを自分で最適化してください。画像を表示しない/ビデオとオーディオ...

CSS3 クリアフロートメソッドの例

1. 目的この記事を通じて、誰もがフロートをクリアする原理と方法を理解し、最終的にこの記事が最良であ...

Nodejs でモジュール fs ファイルシステムを使用する方法

目次概要ファイル記述子同期、非同期、Promise同期書き込み非同期書き込み(推奨)約束​​の書き方...

HTML検証 HTML検証

HTML 検証はHTML 検証を指します。これは、HTML ドキュメントを分析し、標準の HTML ...

mysql 実行プラン ID が空である (UNION キーワード) の詳細な説明

導入作業プロセス中に、遅いクエリが調整されることがあります。 MySQL SQL ステートメントのチ...

Ubuntu16.04 インストール mysql5.7.22 グラフィックチュートリアル

VMware12.0+Ubuntu16.04+MySQL5.7.22 インストールチュートリアルの詳...

Linux で MySQL スケジュールタスクを実装する方法

前提: ストアド プロシージャは、毎日午後 10 時から午前 5 時まで 10 分ごとに実行されます...

Flash での HTML と CSS の適用

Flash での HTML と CSS の適用:同僚の Den が Flash で HTML と C...

HTML ウェブページでのアンカー(名前付きアンカー)の使用の概要

以下の情報はインターネットから収集したものです1. アンカーは、Web ページ作成におけるハイパーリ...

DockerでMongoDBコンテナをデプロイする方法

目次Dockerとは展開する1. イメージをプルする2. 画像を表示する3. コンテナを実行する4....