1. ホーム
  2. http

WebSocketサーバーは、複数の着信接続要求をどのように処理するのですか?

2023-09-02 21:01:33

質問

によると ここに :

<ブロッククオート

HTTP Upgrade ヘッダは、サーバに を切り替えます。 アプリケーション層のプロトコルを HTTP から WebSocket プロトコルに切り替えるよう .

クライアントハンドシェイクは、IE10 とサーバー間の HTTP-on-TCP 接続を確立しました。 とサーバーの間に HTTP-on-TCP 接続を確立しました。サーバーが101応答を返した後、アプリケーション層のプロトコルはHTTPからWebSocketに切り替わります。 アプリケーション層のプロトコルは、HTTP から WebSocket に切り替わり、以前に確立した TCP 接続を使用します。 に切り替わります。

HTTP は完全に除外されます この時点で 軽量な 軽量な WebSocket ワイヤ・プロトコルを使用して、メッセージの送受信が可能になりました。

WebSocket ワイヤプロトコルを使用すると、いつでもどちらのエンドポイントでもメッセージを送受信できます。

つまり、私の理解では、1番目のクライアントがサーバーとのハンドシェイクを終えた後、サーバーの80ポートが を独占する を WebSocket プロトコルによって独占しています。そして、その HTTP は 80 ポートで動作しなくなりました。 .

では、2番目のクライアントはどのようにしてサーバとハンドシェイクを交わすことができたのでしょうか。 結局のところ、WebSocket のハンドシェイクは HTTP フォーマットです。

追加1

これまでのすべての回答ありがとうございました。本当に助かります。

これで理解したのですが、同じサーバーの80番ポートが 共有 複数で TCP の接続が可能です。そしてこの共有は全く問題ありません なぜなら TCP という 5 要素のタプルで識別されるからです。 Jan-Philip Gehrcke が指摘されています。

少し考えを付け加えたいと思います。

どちらも WebSocketHTTP は単なるアプリケーションレベルのプロトコルに過ぎません。 通常 に依存しています。 TCP プロトコルに依存しています。

なぜ80番ポートを選ぶのですか?

WebSocketの設計では、以下の理由で意図的にサーバーの80番ポートを選択します。 ハンドシェイクとそれに続く通信の両方 . 設計者は、WebSocketの通信を以下のようにしたいのだと思います。 のように見える 通常のHTTP通信のように トランスポートレベルの観点から (すなわち、サーバーのポート番号は 80 のまま) . しかし jfriend00 の回答によると、このトリックは必ずしもネットワークインフラを欺くものではないそうです。

からどのようにプロトコルが移行するのでしょうか? HTTP から ウェブソケット が起こるか?

RFC 6455 より - WebSocket プロトコル

基本的には、Web の制約の中で可能な限り生の TCP をスクリプトに公開することに近づけるよう意図されています。 スクリプトに公開するのと同じようにすることを意図しています。また サーバーが HTTP サーバーとポートを共有できるような設計になっています。 サーバとポートを共有できるように設計されています。ある クライアントとサーバーのメッセージングを確立するために、他のプロトコルを使用することも概念的には可能です。 しかし、WebSocket の意図は、クライアントとサーバーのメッセージングを確立するために、比較的単純なプロトコルを提供することです。 HTTP と共存できる比較的単純なプロトコルを提供することであり、プロキシなどの展開された HTTP インフラストラクチャ (プロキシなど) と共存でき、セキュリティを考慮した場合、TCP に限りなく近い比較的単純なプロトコルを提供することです。 このようなインフラで使用するために、セキュリティを考慮した上で、TCP に近い安全なプロトコルを提供します。 使用法を簡略化し、単純なものを単純に保つための的を射た追加を行う。 メッセージのセマンティックの追加など)。

というわけで、私は以下の文章について間違っていると思います。

ハンドシェイクのリクエスト を模倣する HTTP リクエストを模倣していますが、その後の通信は を模倣したものではありません。ハンドシェイクのリクエストはポート80でサーバーに届きます。 80番ポートなので、サーバーはこれをHTTPプロトコルで扱います。そのため、WebSocketのハンドシェイクリクエストはHTTP形式である必要があります。 だとすると、HTTPプロトコルは MUST に変更/拡張されなければなりません。 WebSocket 固有のものを認識できるように修正/拡張されなければなりません。そうでなければ そうでなければ に降伏します。 WebSocketのプロトコルです。

このように理解すればよいと思います。

WebSocketの通信は、まず 有効な HTTP リクエストから始まります。 クライアントからサーバーへの つまり、HTTP プロトコルに従うのはサーバーです。 に従ってハンドシェイクリクエストをパースし 特定 を求める プロトコルを変更します。そしてプロトコルを切り替えるのはサーバーなのです。ですから HTTPプロトコルは変更する必要がない。HTTPプロトコルはWebSocketを知る必要すらありません WebSocketについて知る必要もありません。

WebSocket と Comet

つまり、WebSocket は comet 技術とは異なり、WebSoket は双方向通信の問題を解決するために、現在の HTTP レルム内に自分自身を限定しないという点です。

追加 2

関連する質問です。 ブラウザはどのように80ポートでWebサーバとの接続を確立するのですか?詳細は?

どのように解決するのですか?

あなたの質問は素晴らしいです。

システムコールを含む観点から回答してみたいと思います。 listen()accept() . この2つの呼び出しの動作を理解することは、非常に洞察的であり、あなたの質問に答えるのに十分だと私は思っています。

ネタバレ》 TCP/IP がどのように機能するかを調べることで、あなたの質問に答えることができます :-)

質問の核となる部分については、HTTP か WebSocket かによる違いは本当にありません。共通の基盤は、IP 上の TCP です。HTTP リクエストを送信するには、2 つの当事者間で確立された TCP/IP 接続が必要です (これについては、もう少し詳しく説明しようと思います。 はこちら ).

単純なウェブブラウザ/ウェブサーバのシナリオの場合

  1. まず、両者間に TCP 接続が確立されます (クライアントによって開始されます)。
  2. を介して HTTP リクエストが送信されます。 その TCP 接続 (クライアントからサーバーへ)
  3. を経由して、HTTP レスポンスが送信されます。 同じ TCP 接続 (サーバーからクライアントへの逆方向) を通して送信されます。

この交換の後、基礎となる TCP 接続はもう必要なく、通常は破棄/切断されます。いわゆる HTTP アップグレード要求の場合 (次のように考えることができます: "ヘイ、サーバー! Hey, server! Please upgrade this to a WebSocket connection!")、基盤となる TCP 接続はそのまま生き続け、WebSocket 通信は最初に作成されたのとまったく同じ TCP 接続を介して行われます(上記 (1) のステップ)。

これにより、WebSocket と HTTP の間の重要な違いは、高レベルのプロトコルの切り替え (HTTP から WebSocket への切り替え) であることが明らかになります。 基礎となるトランスポート チャネル (TCP/IP 接続) を変更することなく、高レベルのプロトコル (HTTP から WebSocket へ) を切り替えることです。

同じソケットを介した複数の IP 接続の試行を処理する、方法は?

これは私自身がかつて悩んでいたトピックで、少し直感的でないため多くの人が理解できていません。しかし、オペレーティング システムによって提供される基本的なソケット関連のシステム コールがどのように動作しているかを理解すると、この概念は実際には非常に単純です。

まず、IP 接続が 一意的 によって定義されます。 5 の情報によって定義されます。

マシンAのIP:PORT そして マシンBのIP:PORT そして プロトコル(TCPまたはUDP)

では ソケット オブジェクトは、しばしば接続を表すと考えられています。しかし、それは完全に正しいわけではありません。それらは異なるものを表現することができます:それらは能動的であったり受動的であったりします。のソケットオブジェクトは パッシブ/リスン モードのソケットオブジェクトはかなり特殊なことをしますし、それはあなたの質問に答えるために重要です。

http://linux.die.net/man/2/listen は言う。

listen() は sockfd によって参照されるソケットをパッシブソケットとしてマークします。 つまり、accept(2) を使って入ってくる接続要求を受け入れるために使われるソケットです。 accept(2) を使って接続要求を受け入れるために使われるソケットです。

つまり パッシブ ソケットを作ることができます。定義によれば、このようなソケットは決して接続を表すことはできません。単に接続要求を待ち受けるだけです。

に向かいましょう。 accept() ( http://linux.die.net/man/2/accept ):

accept()システムコールは、コネクション型のソケットタイプ (sock_stream, sock_seqpacket) で使用されます。これは、リスニングしているソケットの保留中の接続キューから、最初の接続 接続待ちのキューにある最初の接続要求を取り出します。 sockfdを抽出し、新しい接続ソケットを生成し、そのソケットを参照する新しいファイル記述子を返す。 ディスクリプタを返す。新しく作成されたソケットは、リスニング状態ではなく はリスニング状態ではない。元のソケット sockfd はこの呼び出しに影響されない。 この呼び出しの影響を受けない。

これをじっくりと消化しましょう。これで本当にあなたの質問に答えられると思います。

accept() の状態を変更しません。 パッシブ ソケットの状態を変更しません。これは アクティブ(接続済み) ソケットを返します(このようなソケットは、上記の5つの情報の状態を表します。簡単でしょう?)。

通常、この新しく作成されたアクティブなソケットオブジェクトは、その後、他のプロセスやスレッド、または単に接続の世話をするエンティティ"に引き渡されます。その後 accept() はこの接続されたソケットオブジェクトを返します。 accept() を呼び出すことができます。 を再び をパッシブソケット上で何度も何度も呼び出すことができます。 アクセプトループ .

しかし accept() を呼び出すには時間がかかりますよね?接続要求が来なくても大丈夫なのでしょうか?今引用したヘルプテキストにはもっと重要な情報があります:保留中の接続要求のキューがあるのです! これは、オペレーティング システムの TCP/IP スタックによって自動的に処理されます。

つまり accept() は入ってくる接続要求だけを扱うことができ 一個一個 のみであり、高速に、あるいは(準)同時に着信した場合でも、着信要求を見逃すことはありません。の動作は accept() の動作は、マシンが処理できる着信接続要求の頻度を制限していると言えます。しかし、これは高速なシステムコールであり、実際には他の制限が最初に襲ってきます -- 通常は、受け入れられたすべての接続を処理することに関連するものです。 これまでのところ .