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

我们正在开发一个只能在现代浏览器(IE10 +)上运行的Web应用程序,原因不同。

我们实现的一个特性是Socket.io 1.x. 但是,默认情况下,Socket.io客户端会尝试支持较旧的浏览器,因此它会启动长轮询连接,然后将其更新到WebSocket。 这是浪费时间和资源,因为我们确定浏览器支持WS。

我search了四周,我只能find这个维基页面 ,但是,这是关于Socket.io 0.9。

最终,我find了engine.io-client的文档 (其中Socket.io-client基于1.x分支)。 这是我写的代码, 似乎正在工作。 但是,我想知道是否正确或者我做错了什么:

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

奇怪的是,只是将transports属性设置为只有websockets的数组是不够的。 我也必须禁用upgrade 。 它是否正确?

更新

我做了一些新的发现。

只有transports设置为['websocket'] ,启用或不启用任何upgrade 。 这是正常的吗?

socket.io有两种types的“升级”。 首先(在socket.io 1.0+中),socket.io使用http轮询请求启动所有的连接,实际上它可以用一个http请求来交换一些初始数据。 然后,在那之后的某个时刻,它会尝试实际启动一个webSocket连接。 webSocket连接是通过发送一个指定upgrade: websocket的特定types的http请求完成的upgrade: websocket头部,服务器可以响应它是否支持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的支持,所以这排除了旧版本IE尚未支持webSocket兼容。 如果你想保持兼容性,那就让socket.io最初做一些事情。


以下是从http到webSocket协议升级的更多信息。

webSockets协议使用HTTP连接启动每个webSocket。 这就是所有的webSockets的工作方式。 该HTTP连接包含一些标题,表明浏览器将“喜欢”升级到webSockets协议。 如果服务器支持该协议,则它会响应告诉客户端它将升级到webSocket协议,然后该套接字将从HTTP协议切换到webSocket协议。 这是如何devisewebSocket连接的工作。 所以,你看到你的webSocket连接以HTTP连接开始的事实是100%正常的。

你可以configurationsocket.io永远不要使用长轮询,如果这让你感觉更好,但这不会改变这个事实,即webSocket连接仍然会启动一个HTTP连接,然后升级到webSocket协议,它不会改善支持webSockets的现代浏览器的运行效率。 但是,这样做会使您的连接在旧版浏览器中无法使用。

为了让Socket.IO只使用WebSocket,而不是先使用一些XHR请求,只需将其添加到Node服务器:

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

并在客户端添加这个:

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

这告诉Socket.IO只使用WebSocket协议,而不是别的; 它更干净,更快速,并且在客户端和服务器端使用更less的资源。

现在你只会在你的networking请求列表中看到一个单独的WebSocket连接,请记住IE9和更早版本不能使用WebSocket。

我发布的答案是因为接受的答案是不正确的 – 它将长轮询AJAX的Socket.IO升级与WSS协议“连接:升级”请求的WebSocket混淆。 问题不在于WebSocket连接是以HTTP方式启动,而是被升级到了WebSocket – 怎么可能呢? 但是,即使在支持WebSocket的浏览器上,Socket.IO也是以长轮询的AJAX连接开始的,并且在交换一些stream量之后才会进行升级。 在Firefox或Chrome的开发者工具中很容易看到。

这个问题的作者在他的观察中是正确的。 Socket.IO中的“升级”并不是指常被误解的HTTP到WSS协议升级,而是从长轮询AJAX连接升级到WebSocket的Socket.IO连接升级。 如果您已经开始使用WebSocket(这不是默认设置),那么升级false将不起作用,因为您不需要升级。 如果你开始轮询和禁用升级,那么它保持这种方式,并不升级到WebSocket。

如果你想避免长轮询开始,请参阅阿诺德尼克斯蒂尔的答案。 我将更详细地解释发生了什么。

这是我在使用简单的WebSocket和Socket.IO应用程序的实验中观察到的:

的WebSocket

2个请求,1.50 KB,0.05秒

从这两个请求:

  1. HTML页面本身
  2. 连接升级到WebSocket

(连接升级请求在具有101交换协议响应的开发人员工具上可见。)

Socket.IO

6个请求,181.56 KB,0.25秒

从这6个要求:

  1. HTML页面本身
  2. Socket.IO的JavaScript(180千字节)
  3. 首先长时间轮询AJAX请求
  4. 第二长轮询AJAX请求
  5. 第三轮投票AJAX请求
  6. 连接升级到WebSocket

细节

我在本地主机上得到的WebSocket结果:

WebSocket结果 -  websocket-vs-socket.io模块

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

Socket.IO结果 -  websocket-vs-socket.io模块

testing自己

我在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 

看到这个答案更多的信息。

我想我应该增加上面所接受的答案,好像有人想要消除XHR轮询运输并立即启动websocket。 下面的代码只是给出一个实现的想法:

 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,我相信这是原来的问题。 我希望这可以帮助那里的人…