[英]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。
如果你想避免從長輪詢開始,請參閱arnold和Nick Steele的答案。 我將更詳細地解釋發生了什么。
這是我在使用簡單的WebSocket和Socket.IO應用程序的實驗中觀察到的:
從這2個請求:
(連接升級請求在具有101個交換協議響應的開發人員工具上可見。)
從這6個請求中:
我在localhost上獲得的WebSocket結果:
我在localhost上得到的Socket.IO結果:
# 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.