web-dev-qa-db-ja.com

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

here によると:

HTTPアップグレードヘッダーは、サーバーがアプリケーション層プロトコルをHTTPからWebSocketプロトコルに切り替えることを要求します

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

HTTPはこの時点では完全に画像から外れています。軽量のWebSocketワイヤプロトコルを使用して、いつでもエンドポイントがメッセージを送受信できるようになりました。

したがって、私の理解では、最初のクライアントがサーバーとのハンドシェイクを完了した後、サーバーの80ポートはmonopolizedWebSocketプロトコルによる。また、HTTPは80ポートで動作しなくなりました

それでは、2番目のクライアントはサーバーとハンドシェイクをどのように交換できますか。 結局、WebSocketハンドシェイクはHTTP形式です。

ADD 1

これまでのすべての答えをありがとう。彼らは本当に役に立ちます。

今、私は同じサーバーの80ポートが複数のTCP接続によってsharedであることを理解しています。 TCP接続はJan-Philip Gehrckeが指摘した5要素のタプルによって識別されるため、この共有はまったく問題ありません。

いくつかの考えを追加したいと思います。

WebSocketHTTPは両方とも、単なるアプリケーションレベルのプロトコルです。 通常両方ともTCPプロトコルをトランスポートとして使用します。

ポート80を選択する理由

WebSocketの設計では、ハンドシェイクと後続の通信の両方でサーバーのポート80を意図的に選択します。デザイナーは、WebSocket通信通常のHTTP通信のようにトランスポートレベルの観点から見たいと考えています(つまり、サーバーのポート番号はまだ80)です。しかし、jfriend00の答えによると、このトリックは必ずしもネットワークインフラストラクチャをだますわけではありません。

プロトコルは[〜#〜] http [〜#〜]からWebSocketにどのように移行しますか?

RFC 6455-WebSocketプロトコルから

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

だから私は次の文で間違っていると思う:

ハンドシェイクリクエストmimicHTTPリクエストですが、その後の通信はそうではありません。ハンドシェイク要求はポート80でサーバーに到着します。80ポートであるため、サーバーはHTTPプロトコルで処理します。そして、それがWebSocketハンドシェイクリクエストがHTTP形式でなければならない理由です。もしそうなら、HTTPプロトコル[〜#〜] must [〜#〜] これらのWebSocket固有のものを認識するように変更/拡張する。そうしないと、yield toWebSocketプロトコルのはずです。

私はそれがこのように理解されるべきだと思う:

WebSocket通信は、クライアントからサーバーへのvalidHTTP要求で始まります。したがって、HTTPプロトコルに従ってハンドシェイク要求を解析し、identifyプロトコルの変更を要求するのはサーバーです。そして、プロトコルを切り替えるのはサーバーです。したがって、HTTPプロトコルを変更する必要はありません。 HTTPプロトコルはWebSocketについて知る必要さえありません。

WebSocketとComet

そのため、WebSocketは、双方向通信の問題を解決するためにWebSoketが現在のHTTPレルム内で自身を制限しないという点で、 Comet テクノロジーとは異なります。

追加2

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

52
smwikipedia

他の回答はすでに役立ちます。あなたの質問は非常に良いものであり、listen()accept()を含む観点から答えたいと思います。これら2つのシステムコールの動作は、質問に答えるのに十分なはずです。

TCP/IPの仕組みに興味があります!

質問の中核部分については、実際にはHTTPまたはWebSocketに依存する違いはありません。共通の基盤はIPを介してTCPであり、質問に答えるのに十分です。 WebSocketとの関係TCP(もう少し詳しく説明しようとしました ここで ):HTTPリクエストを送信するには、2者間でTCP/IP接続を確立する必要があります。単純なWebブラウザー/ Webサーバーのシナリオの場合

  1. まず、TCP接続は両方の間で確立されます(クライアントによって開始されます)
  2. 次に、HTTP要求がthatTCP接続(クライアントからサーバーへ)を介して送信されます)
  3. 次に、HTTP応答がsameTCP接続(サーバーからクライアントへの逆方向))を介して送信されます

この交換後、基盤となるTCP接続は必要なくなり、通常は破棄/切断されます。HTTPアップグレードリクエストの場合、基盤となるTCP接続生き続け、WebSocket通信は最初に作成されたのとまったく同じTCP接続を経由します(上記のステップ(1)))。

ご覧のとおり、WebSocketと標準HTTPの唯一の違いは、基礎となるトランスポートチャネル(TCP/IP接続)を変更せずに、高レベルプロトコル(HTTPからWebSocketへ)を切り替えることです。

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

これは私がかつて自分と苦労していたトピックであり、多くの人が理解していないことです。ただし、オペレーティングシステムによって提供される基本的なソケット関連のシステムコールがどのように機能するかを理解している場合、概念は実際には非常に単純です。

まず、IP接続はfiveの情報によって一意に定義されることを理解する必要があります。

IP:マシンAのポートおよびIP:マシンBのポートおよびプロトコル(TCPまたはUDP)

現在、socketオブジェクトは多くの場合、接続を表すと考えられています。しかし、それは完全に真実ではありません。それらは異なるものを表す場合があります。アクティブまたはパッシブのいずれかです。passive/listenモードのソケットオブジェクトは非常に特別なことを行います。これは質問に答えるために重要です。 http://linux.die.net/man/2/listen のコメント:

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

したがって、着信接続要求をリッスンするpassiveソケットを作成できます。定義上、このようなソケットは接続を表すことはできません。接続要求をリッスンするだけです。

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

Accept()システムコールは、接続ベースのソケットタイプ(SOCK_STREAM、SOCK_SEQPACKET)で使用されます。待機しているソケットsockfdの保留中の接続のキューにある最初の接続要求を抽出し、新しい接続ソケットを作成し、そのソケットを参照する新しいファイル記述子を返します。新しく作成されたソケットはリスニング状態ではありません。元のソケットsockfdは、この呼び出しの影響を受けません。

あなたの質問に答えるために知っておく必要があるのはそれだけです。 accept()は、前に作成されたpassiveソケットの状態を変更しません。active(connected)ソケットを返します(そのようなソケットは、上記の5つの情報状態を表します-簡単ですか?)。通常、この新しく作成されたアクティブソケットオブジェクトは、接続を処理する別のプロセスまたはスレッド、または単に「エンティティ」に渡されます。 accept()がこの接続されたソケットオブジェクトを返した後、accept()をパッシブソケットでagain呼び出すことができます。accept loopとして知られています。しかし、accept()の呼び出しには時間がかかりますよね?着信接続要求を見逃すことはありませんか?引用されたばかりのヘルプテキストにはさらに重要な情報があります。保留中の接続要求のキューがあります。オペレーティングシステムのTCP/IPスタックによって自動的に処理されます。つまり、accept()は着信接続要求one-by-oneのみを処理できますが、高レートまたは(準)同時に。 accept()の動作は、マシンが処理できる接続要求の頻度を制限していると言えます。ただし、これは高速なシステムコールであり、実際には、他の制限が最初に当たります。通常、これまでに受け入れられたすべての接続の処理に関連する制限です

66

ここで欠けていると思われる比較的簡単なことは、サーバーへの各接続(特にここのHTTPサーバーへの接続)が独自のソケットを作成することですその後、そのソケットで実行されます。 1つのソケットで発生することは、完全に独立しています現在接続されている他のソケットで発生することです。そのため、1つのソケットがwebSocketプロトコルに切り替えられても、他の現在または着信のソケット接続に何が起こるかは変わりません。それらは、彼らがどのように処理されるかを自分で決めます。

そのため、オープンソケットはwebSocketプロトコルを使用できますが、他の着信接続は通常のHTTPリクエストまたは新しいwebSocket接続を作成するリクエストです。

したがって、このタイプのシーケンスを使用できます。

  1. クライアントAは、HTTP要求を使用してポート80でサーバーに接続し、webSocket接続を開始します。このプロセスにより、2つの間にソケットが作成されます。
  2. サーバーはyesに応答し、webSocketリクエストへのアップグレードに応答し、クライアントとサーバーの両方がプロトコルを切り替えますこのソケットのみはwebSocketにプロトコル。
  3. クライアントAとサーバーは、webSocketプロトコルを使用してパケットの交換を開始し、今後数時間は交換を続けます。
  4. クライアントBは、通常のHTTP要求を使用してポート80で同じサーバーに接続します。このプロセスにより、2つの間に新しいソケットが作成されます。
  5. サーバーは、着信要求が通常のHTTP要求であると認識し、応答を送信します。
  6. クライアントBが応答を受信すると、ソケットは閉じられます。
  7. クライアントCは、HTTP要求を使用してポート80で同じサーバーに接続し、webSocketにアップグレードします。
  8. サーバーはyesに応答し、webSocketリクエストへのアップグレードに応答し、クライアントとサーバーの両方がプロトコルを切り替えますこのソケットのみはwebSocketにプロトコル。
  9. この時点で、webSocketプロトコルを使用して通信できる2つのオープンソケットがあり、サーバーは通常のHTTPリクエストまたはwebSocketプロトコルへのアップグレードのリクエストである新しい接続をまだ受け付けています。

そのため、サーバーは常にポート80で新しい接続を受け入れており、それらの新しい接続は通常のHTTPリクエストでも、webSocketプロトコルへのアップグレード(したがってwebSocket接続を開始する)リクエストであるHTTPリクエストでもかまいません。そして、これがすべて行われている間、すでに確立されているwebSocket接続は、webSocketプロトコルを使用して独自のソケットを介して通信しています。

WebSocket接続および通信スキームは、次の特性を持つように非常に慎重に設計されました。

  1. 新しいポートは必要ありません。着信ポート(最も一般的にはポート80)は、通常のHTTP要求とwebSocket通信の両方に使用できます。
  2. 新しいポートは必要なかったため、ファイアウォールまたは他のネットワークインフラストラクチャの変更は「通常」必要ありませんでした。判明したように、HTTPトラフィックを予期している一部のプロキシまたはキャッシュは、webSocketプロトコルのトラフィックを処理(または回避)するために変更する必要があるため、常にそうであるとは限りません。
  3. 同じサーバープロセスで、HTTP要求とwebSocket要求の両方を簡単に処理できます。
  4. HTTP Cookieやその他のHTTPベースの認証手段は、webSocket接続のセットアップ中に使用できます。

さらなる質問への回答:

1)80をデフォルトポートとして選択する理由トランスポートレベルの観点から、デザイナーはWebSocket通信を通常のHTTP通信のように見せたいですか? (つまり、サーバーポートは古き良き80です)。

はい、すぐ上の私のポイント1-4をご覧ください。 webSocketは既存のHTTPチャネル上に確立できるため、通常はネットワークインフラストラクチャを変更する必要はありません。既存のHTTPサーバーにはwebSocketサポートを追加できるだけなので、新しいサーバーやサーバープロセスは必要ありません。

2)サーバーでプロトコルシフトがどのように発生するかを想像しようとしています。 HTTPまたはWebSocketトラフィックを処理するためのさまざまなソフトウェアモジュールがあることをイメージしています。最初のサーバーは、HTTPモジュールを使用して通常のHTTP要求を処理します。アップグレードリクエストを見つけると、WebSocketモジュールを使用するように切り替わります。

さまざまなサーバーアーキテクチャが、webSocketパケットとHTTPリクエストの区分を別々に処理します。場合によっては、webSocket接続が新しいプロセスに転送されることもあります。また、同じプロセス内の異なるイベントハンドラーで、ソケット上の着信パケットトラフィック用に登録されているものもありますが、これは現在webSocketプロトコルに切り替えられています。これは、WebサーバーアーキテクチャとwebSocketトラフィックの処理方法に完全に依存しています。 webSocketアプリのサーバー側を実装する開発者は、特定のWebサーバーアーキテクチャと互換性のある既存のwebSocket実装を選択し、そのフレームワーク内で機能するコードを記述する可能性が高くなります。

私の場合、node.js(これは私のサーバーアーキテクチャです)で動作するsocket.ioライブラリを選択しました。このライブラリは、webSocketを新しく接続するためのイベントをサポートするオブジェクトを提供し、次に着信メッセージの読み取りまたは発信メッセージの送信のための他のイベントのセットを提供します。最初のwebSocket接続の詳細はすべてライブラリによって処理され、そのことについて心配する必要はありません。接続を確立する前に認証を要求する場合、socket.ioライブラリを使用してプラグインすることができます。その後、任意のクライアントからメッセージを受信したり、単一のクライアントにメッセージを送信したり、すべてのクライアントに情報をブロードキャストしたりできます。 Webページの表示が常に最新であるように、Webページの情報を「ライブ」に保つために、主にブロードキャストに使用しています。サーバーで値が変更されるたびに、接続されているすべてのクライアントに新しい値をブロードキャストします。

19
jfriend00

あなたの質問に答えるために:ポート80への同時WebsocketとHTTP接続が処理されます...

ポート80への同時HTTP接続が処理されるのとまったく同じ方法です!

つまり:満足のいくTCPハンドシェイクで、serviceip:80でリッスンしているサービスは、新しいプロセスまたはスレッドを作成し、その接続のすべての通信をそれにハンドオーバしますjfriend00が正しく指摘したように、非同期nodejsが行うように、そのイベントに関連付けられたコールバック。

次に、キュー内の次の着信要求を待機または処理します。

HTTP 1.1とUPGRADEリクエストがこのすべてでどの部分を再生するかを知りたい場合は、この MSDNの記事 で非常に明確になります。

WebSocketプロトコルには2つの部分があります。アップグレードされた接続を確立するためのハンドシェイクと、実際のデータ転送です。最初に、クライアントは、「Upgrade:websocket」および「Connection:Upgrade」ヘッダーと、使用されているバージョンを確立してハンドシェイクをセットアップするためのいくつかのプロトコル固有のヘッダーを使用して、Websocket接続を要求します。サーバーは、プロトコルをサポートしている場合、同じ「Upgrade:websocket」および「Connection:Upgrade」ヘッダーで応答し、ハンドシェイクを完了します。ハンドシェイクが正常に完了すると、データ転送が開始されます。

通常、WebsocketサービスのみがWebサーバーに組み込まれていないため、ポート80でリッスンすることは意図されていません。Webサーバーの透過的な転送のおかげで、Websocketサービスを介してアクセスできます。 Apache Webサーバーは mod_proxy_wstunnel を使用してそれを行います。

もちろん、組み込みのWebソケット実装を備えたWebサーバーを使用することもできます。 Apache Tomcat など。

主なものは次のとおりです。WebsocketプロトコルはHTTPではありません。別の目的を果たします。これは、TCPの上に構築された独立したアプリケーション層通信プロトコルです(ただし、TCPは必須ではありませんが、適合するトランスポート層プロトコルですWebsocketsアプリケーション層プロトコルの要件)。

Websocketサービスは、Webサーバーサービスとともに実行されるPARALLELサービスです。

Websocketプロトコルを使用します。これは、最新のWebブラウザーがサポートしており、インターフェースのクライアント部分を実装しています。

Websocketクライアント(通常はWebブラウザー)とそのサービスの間に永続的な非HTTP接続を確立するために、Websocketサービスをセットアップまたは構築します。

主な利点は次のとおりです。Websocketサービスは、必要なときにいつでもクライアントにメッセージを送信できます( "仲間の1人が接続しました!" ""チームクライアントの明示的なREQUESTの更新を待つ代わりに、ゴールを決めただけです! ")。

HTTP 1.1を使用して永続的な接続を確立できますが、HTTPはリソースのセットUPON REQUESTを提供してから接続を閉じる以外の目的ではありません。

最近まで、Websocketのサポートがすべての主要なブラウザーで利用可能になる前は、Webアプリケーションにリアルタイム更新を実装するための選択肢は2つしかありませんでした。

  • AJAX長いポーリングリクエストの実装。これは苦痛で非効率的なプロセスです。

  • 更新サービスとの非HTTP接続を確立できるようにするために、ブラウザプラグイン(たとえばJavaアプレットサポートプラグイン)を使用/構築する。長いポーリング。

サービスの共有リスニングポート(任意のTCPポートであり、ほとんどのWebサーバーはWebソケット接続の透過的な転送をサポートしているため、インターネットに開かれている必要はありません) )、他のTCPサービス:サービスはそれをリッスンし、TCPハンドシェイクがTCPサービスがクライアントと通信するためのソケットが存在します。

通常、特定のTCPソケット(server_ip:service_TCP_port)でリッスンしているサービスへのすべての接続は、一意のclient_ip:client_TCP_portペアが割り当てられたときに区別されます。client_TCP_portは、使用可能TCPポート)。

Websocket接続ハンドシェイク時に発生するHTTP-> Websocketアプリケーションプロトコルハンドオーバーについて疑問がある場合、および基盤となるTCP接続とは何の関係もない場合、 Jan-Philip Gehrckeの回答 、これは非常に明確で、有益であり、おそらく実際に探していたものです。

5
NotGaeL

それは非常に単純な概念なので、他の失われた魂がそれらの長い説明をすべて読むことなくそれを把握したい場合に備えて、簡単な用語で説明してみましょう。

複数の接続

  1. Webサーバーは接続のリッスンを開始します。これが起こります:

    • Webサーバーのメインプロセスは、ポート80listen状態のパッシブソケットを開きます。 9.9.9.9:809.9.9.9はサーバーIP、80はポートです)。
  2. ブラウザーは、サーバー上の80ポートへの要求を行います。これが起こります:

    • オペレーティングシステム(略してOS)は、クライアントにランダムなアウトバウンドポートを割り当てます。たとえば、1.1.1.1:67471.1.1.1はクライアントIP、6747はランダムポートです)。

    • OSは、送信元アドレス1.1.1.1:6747および宛先アドレス9.9.9.9:80を含むデータパケットを送信します。さまざまなルーターとスイッチを通過し、宛先サーバーに到着します。

  3. サーバーはパケットを受信します。これが起こります:

    • サーバーOSは、パケットの宛先アドレスが自身のIPアドレスの1つであることを確認し、宛先ポートに基づいて、ポート80に関連付けられているアプリケーションに渡します。

    • Webサーバーのメインプロセスは、新しいアクティブソケットを作成する接続を受け入れます。その後、通常はアクティブなソケットを引き継ぐ新しい子プロセスをフォークします。パッシブソケットは開いたままで、新しい着信接続を受け入れます。

これで、サーバーからクライアントに送信されるすべてのパケットには次のアドレスが含まれます。

  • ソース:9.9.9.9:1553;宛先:1.1.1.1:80

また、クライアントからサーバーに送信されるすべてのパケットには、次のアドレスが含まれます。

  • ソース:1.1.1.1:80;宛先:9.9.9.9:1553

HTTP-> WebSocketハンドシェイク

HTTPはテキストベースのプロトコルです。使用可能なコマンドのリストについては、 HTTP wiki を参照してください。ブラウザはこれらのコマンドの1つを送信し、Webサーバーはそれに応じて応答します。

WebSocketはHTTPに基づいていません。これは、複数のメッセージストリームを同時に双方向に送信できるバイナリプロトコルです(全二重モード)。そのため、たとえば HTTP/2 のように、新しいHTTP標準を導入せずにWebSocket接続を直接確立することはできません。ただし、次の場合にのみ可能です。

  1. WebSocketサポート HTTP動詞/リクエスト

  2. WebSocket固有の通信用に80とは異なる新しい専用ポートがありました。

最初のプロトコルはプロトコルの範囲内にありませんでしたが、2番目は既存のWebインフラストラクチャを破壊します。クライアント/ブラウザは同じサーバーと複数のHTTP接続を確立できるため、それらの一部をHTTPからWebSocketに切り替えることは両方の長所です。同じポート80を維持しますが、HTTPとは異なるプロトコルを許可します。切り替えは、クライアントによって開始された protocol handshake によって行われます。

1
Greg