web-dev-qa-db-ja.com

Socket.io 1.x:WebSocketのみを使用しますか?

さまざまな理由により、最新のブラウザ(IE10 +)でのみ実行されるWebアプリケーションを開発しています。

実装した機能の1つはSocket.io 1.xです。ただし、デフォルトでは、Socket.ioクライアントは古いブラウザーをサポートしようとするため、長いポーリングで接続を開始してからWebSocketに更新します。ブラウザがWSをサポートしていることは確かであるため、これは時間とリソースの無駄です。

私はあちこち検索しましたが、見つけることができるのは このwikiページ ですが、これはSocket.io 0.9についてです。

最終的に、 engine.io-clientのドキュメント (Socket.io-clientは1.xブランチに基づいています)が見つかりました。これは私が書いたコードで、seems動作しているようです。しかし、私はそれが正しいかどうか、または何か間違ったことをしているかどうかを知りたいです:

io.connect('https://...', {
    upgrade: false,
    transports: ['websocket']
})

奇妙なことに、transportsプロパティをwebsocketsのみの配列に設定するだけでは不十分でした。 upgradeも無効にする必要がありました。これは正しいです?

更新

私はいくつかの新しい発見をしました。

transports['websocket']のみに設定すると、upgradeが有効かどうかに違いはありません。それは正常ですか?

36
ItalyPaleAle

Socket.ioで発生する「アップグレード」には2つのタイプがあります。最初(socket.io 1.0以降)、socket.ioはすべての接続をhttpポーリングリクエストで開始し、実際にはhttpリクエストだけで初期データを交換する場合があります。その後、その後のある時点で、実際にwebSocket接続を開始しようとします。 webSocket接続は、upgrade: websocketヘッダーを指定する特定のタイプのhttp要求を送信することで行われ、サーバーはwebsocketをサポートするかどうかに関係なく適切に応答できます。サーバーがアップグレードに同意すると、その特定のhttp接続はwebSocketプロトコルに「アップグレード」されます。その時点で、クライアントはwebSocketがサポートされていることを認識し、ポーリングhttpリクエストの使用を停止し、webSocketへのupgradeを完了します。

クライアントでこれを行うことにより、最初のhttpポーリングを完全に防ぐことができます。

var socket = io({transports: ['websocket'], upgrade: false});

これにより、協力するクライアントからの接続のポーリングが防止されます。クライアントがポーリングを使用しないようにするには、これをサーバーに追加できます。

io.set('transports', ['websocket']);

ただし、サーバーでこれを設定すると、最初にhttpポーリングで接続しているsocket.ioクライアントはまったく機能しません。したがって、これはクライアントがポーリングで開始しないように、クライアントの正しい設定とのみ一致する必要があります。

これにより、webSocketsのみを使用したいことが両端に通知され、socket.ioは最初に余分なhttpポーリングをスキップします。公正な警告、これを行うにはwebSocketのサポートが必要なので、これはwebSocketをまだサポートしていないIEの古いバージョンとの互換性を排除します。互換性を維持したい場合は、socket.ioに任せてください最初はいくつかのhttpリクエストがあります。


HttpからwebSocketへのプロトコルのアップグレードに関する詳細情報を以下に示します。

WebSocketsプロトコルは、すべてのwebSocketをHTTP接続で開始します。これがすべてのwebSocketの動作です。そのHTTP接続には、ブラウザがwebSocketsプロトコルへのアップグレードを「希望」することを示すヘッダーがいくつか含まれています。サーバーがそのプロトコルをサポートしている場合、サーバーに応答してwebSocketプロトコルにアップグレードし、そのソケットがHTTPプロトコルからwebSocketプロトコルに切り替わることをクライアントに伝えます。これが、webSocket接続が機能するように設計されている方法です。そのため、HTTP接続で始まるwebSocket接続が表示されるという事実は、100%正常です。

Socket.ioを設定して長時間のポーリングを使用しないように設定できますが、気分が良くなる場合でも、webSocket接続がHTTP接続で開始され、その後webSocketプロトコルにアップグレードされるという事実は変わりません。 webSocketをサポートする最新のブラウザーでの操作の効率。ただし、古いブラウザでは接続が機能しないようにします。

55
jfriend00

最初にいくつかのXHRリクエストではなくWebSocketのみを使用するようSocket.IOに指示するには、これをNodeサーバーに追加するだけです:

io.set('transports', ['websocket']);

そしてクライアントでこれを追加します:

var socket = io({transports: ['websocket']});

これは、Socket.IOにWebSocketプロトコルのみを使用するように指示します。よりクリーンで高速で、クライアント側とサーバー側で使用するリソースが少し少なくなります。

これで、ネットワーク要求リストに単一のWebSocket接続のみが表示されます。IE9以前ではWebSocketを使用できないことに注意してください。

29
Nick Steele

受け入れられた回答が正しくないため、私はその回答を投稿しています-WSSプロトコル「接続:アップグレード」リクエストで、ロングポーリングAJAXからWebSocketへのSocket.IOアップグレードを混同します。問題は、WebSocket接続がHTTPとして開始され、WebSocketにアップグレードされることではありません。どうしてできないのでしょうか? -ただし、Socket.IOは、WebSocketをサポートするブラウザー上でもロングポーリングAJAX接続で開始され、トラフィックを交換した後にのみアップグレードします。 FirefoxまたはChromeの開発者ツールで簡単に確認できます。

質問の著者は彼の観察で正しいです。 Socket.IOの「アップグレード」は、誤解されることが多いHTTPからWSSへのプロトコルアップグレードではなく、長いポーリングAJAX接続からWebSocketへのSocket.IO接続のアップグレードを指します。すでにWebSocketで起動している場合(これはデフォルトではありません)、アップグレードする必要がないため、falseのアップグレードは効果がありません。ポーリングから開始してアップグレードを無効にすると、そのままでWebSocketにアップグレードされません。

で回避したい場合は、arnoldおよびNick Steeleによる回答を参照してくださいロングポーリング。何が起こっているかをより詳しく説明します。

これは、単純なWebSocketおよびSocket.IOアプリで 私の実験 で観察したことです:

WebSocket

2リクエスト、1.50 KB、0.05秒

これらの2つのリクエストから:

  1. HTMLページ自体
  2. webSocketへの接続のアップグレード

(接続のアップグレードリクエストは、101スイッチングプロトコルレスポンスで開発者ツールに表示されます。)

Socket.IO

6リクエスト、181.56 KB、0.25秒

これらの6つのリクエストから:

  1. hTMLページ自体
  2. Socket.IOのJavaScript(180キロバイト)
  3. 最初のロングポーリングAJAXリクエスト
  4. 2番目のロングポーリングAJAXリクエスト
  5. 3番目のロングポーリングAJAXリクエスト
  6. webSocketへの接続のアップグレード

詳細

Localhostで取得したWebSocketの結果:

WebSocket results - websocket-vs-socket.io module

Localhostで取得したSocket.IOの結果:

Socket.IO results - websocket-vs-socket.io module

自分を試す

コードを公開しました npm および GitHub で、自分で実行できます:

# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io

そして、制限に従ってください。アンインストールするには:

# Uninstall:
npm rm -g websocket-vs-socket.io

詳細については、 この回答 を参照してください。

21
rsp

誰かがXHRポーリングトランスポートを削除し、すぐにWebソケットを開始したい場合のように、上記の受け入れられた答えに追加する必要があると思いました。以下のコードは、実装のアイデアを示すためのものです。

var url = serverUrl + "/ssClients"  //ssClients is the socket.io namespace

var connectionOptions =  {
    "force new connection" : true,
    "reconnection": true,
    "reconnectionDelay": 2000,                  //starts with 2 secs delay, then 4, 6, 8, until 60 where it stays forever until it reconnects
    "reconnectionDelayMax" : 60000,             //1 minute maximum delay between connections
    "reconnectionAttempts": "Infinity",         //to prevent dead clients, having the user to having to manually reconnect after a server restart.
    "timeout" : 10000,                           //before connect_error and connect_timeout are emitted.
    "transports" : ["websocket"]                //forces the transport to be only websocket. Server needs to be setup as well/
}
var socket = require("socket.io-client")(url, connectionOptions); 

socket.on("connect", function (_socket) {
    logger.info("Client connected to server: " + clientName);
    logger.info("Transport being used: " + socket.io.engine.transport.name);

    socket.emit("join", clientName, function(_socketId) {  //tell the server the client name
        logger.info("Client received acknowledgement from server: " + _socketId);
        logger.info("Transport being used after acknowledgement: " + socket.io.engine.transport.name);

    });
});

サーバーのセットアップ後、次のように表示されます。

2015-10-23T19:04:30.076Z - info:    Client connected to server: someClientId 
2015-10-23T19:04:30.077Z - info:    Transport being used: websocket 
2015-10-23T19:04:30.081Z - info:    Client received acknowledgement from server: aMH0SmW8CbiL8w5RAAAA
2015-10-23T19:04:30.081Z - info:    Transport being used after acknowledgement: websocket

トランスポートを強制しない場合、websocketの代わりに「ポーリング」が表示されます。ただし、これはクライアント側だけでは起こりません。サーバーもセットアップする必要があります。

var io = require("socket.io")(server, { adapter: adapter, log: false }); //attach io to existing Express (http) server
..
io.set('transports', ['websocket']); //forces client to connect as websockets. If client tries xhr polling, it won't connect.

危険

クライアントが実際にwebsocketプロトコルをサポートしないnot場合、接続は行われず、クライアントはxhr poll error

私が持っているクライアントを制御できるので、これは私にとって完璧に機能しています。したがって、ウェブソケットをすぐに強制する贅沢があります。これが誰かに役立つことを願っています...

8
arnold