簡體   English   中英

Socket.io 1.x:僅使用WebSockets?

[英]Socket.io 1.x: use WebSockets only?

我們正在開發一個僅在現代瀏覽器(IE10 +)上運行的Web應用程序,原因各不相同。

我們實現的功能之一是Socket.io 1.x. 但是,默認情況下,Socket.io客戶端會嘗試支持較舊的瀏覽器,因此它會啟動與長輪詢的連接,然后將其更新到WebSockets。 這是浪費時間和資源,因為我們知道瀏覽器支持WS。

我一直在搜索,我只能找到這個wiki頁面 ,但是,它是關於Socket.io 0.9的。

最后,我找到了engine.io-client的文檔 (Socket.io-client基於1.x分支)。 這是我編寫的代碼, 似乎正在運行。 但是,我想知道它是否正確或者我做錯了什么:

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

奇怪的是,僅將transports屬性設置為僅包含websockets的數組是不夠的; 我還必須禁用upgrade 它是否正確?

更新

我做了一些新的發現。

如果僅將transports設置為['websocket'] ,則無論是否啟用upgrade都不會產生任何差異。 這是正常的嗎?

socket.io發生了兩種類型的“升級”。 首先(在socket.io 1.0+中),socket.io啟動所有與http輪詢請求的連接,它實際上可能只用一個http請求交換一些初始數據。 然后,在此之后的某個時刻,它將嘗試實際啟動webSocket連接。 webSocket連接通過發送指定upgrade: websocket的特定類型的http請求來完成upgrade: websocket標頭,然后服務器可以適當地響應它是否支持websocket。 如果服務器同意升級,則該特定http連接被“升級”為webSocket協議。 此時,客戶端知道webSocket受支持並且它停止使用輪詢http請求,從而完成其upgrade到webSocket。

您可以通過在客戶端上執行此操作來完全阻止初始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協議使用HTTP連接啟動每個webSocket。 這就是所有webSockets的工作方式。 該HTTP連接包含一些標題,表明瀏覽器“喜歡”升級到webSockets協議。 如果服務器支持該協議,則它會響應告知客戶端它將升級到webSocket協議,然后該套接字將從HTTP協議切換到webSocket協議。 這就是webSocket連接的設計方式。 因此,您看到以HTTP連接開頭的webSocket連接的事實是100%正常。

您可以將socket.io配置為永遠不會使用長輪詢,如果這讓您感覺更好,但這不會改變webSocket連接仍將以HTTP連接開始,然后升級到webSocket協議並且不會改善支持webSockets的現代瀏覽器的操作效率。 但是,它會使您的連接無法在舊版瀏覽器中使用。

要告訴Socket.IO僅使用WebSocket而不是首先使用幾個XHR請求,只需將其添加到節點服務器:

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

並在客戶端添加此:

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

這告訴Socket.IO只使用WebSocket協議而不是別的; 它更干凈,更快,並且在客戶端和服務器端使用更少的資源。

現在,您只會在網絡請求列表中看到單個WebSocket連接,請記住IE9及更早版本不能使用WebSocket。

我發布了答案,因為接受的答案是不正確的 - 它將Socket.IO從長輪詢AJAX升級到WebSocket與WSS協議“連接:升級”請求混淆。 問題不在於WebSocket連接是以HTTP身份啟動並升級到WebSocket - 它怎么可能不是? - 但是,即使在支持WebSocket的瀏覽器上,Socket.IO也會以長輪詢AJAX連接開始,並且只在交換一些流量后才進行升級。 在Firefox或Chrome的開發者工具中很容易看到。

這個問題的作者在他的觀察中是正確的。 Socket.IO中的“升級”並不是指HTTP到WSS協議升級,因為它經常被誤解,而是指從長輪詢AJAX連接升級到WebSocket的Socket.IO連接。 如果您已經開始使用WebSocket(這不是默認設置),那么升級false無效,因為您不需要升級。 如果您從輪詢開始並禁用升級,那么它將保持這種狀態,並且不會升級到WebSocket。

如果你想避免從長輪詢開始,請參閱arnoldNick Steele的答案。 我將更詳細地解釋發生了什么。

這是我在使用簡單的WebSocket和Socket.IO應用程序的實驗中觀察到的:

的WebSocket

2個請求,1.50 KB,0.05 s

從這2個請求:

  1. HTML頁面本身
  2. 連接升級到WebSocket

(連接升級請求在具有101個交換協議響應的開發人員工具上可見。)

Socket.IO

6個請求,181.56 KB,0.25 s

從這6個請求中:

  1. HTML頁面本身
  2. Socket.IO的JavaScript(180千字節)
  3. 第一次長輪詢AJAX請求
  4. 第二次長輪詢AJAX請求
  5. 第三次長輪詢AJAX請求
  6. 連接升級到WebSocket

細節

我在localhost上獲得的WebSocket結果:

WebSocket結果 -  websocket-vs-socket.io模塊

我在localhost上得到的Socket.IO結果:

Socket.IO結果 -  websocket-vs-socket.io模塊

測試自己

在npmGitHub 發布了代碼,你可以自己運行它:

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

並遵循限制。 要卸載:

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

有關詳細信息,請參閱此答案

我認為我應該添加上面接受的答案,好像有人想要消除XHR輪詢傳輸並立即啟動websockets。 下面的代碼只是為了說明實現:

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協議,連接不會發生,客戶端將報告一個xhr poll error

這對我來說非常合適,因為我可以控制我擁有的客戶,因此我可以立即強制使用websockets,我相信這是原始問題所要求的。 我希望這可以幫助那些人......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM