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秒
从这两个请求:
- HTML页面本身
- 连接升级到WebSocket
(连接升级请求在具有101交换协议响应的开发人员工具上可见。)
Socket.IO
6个请求,181.56 KB,0.25秒
从这6个要求:
- HTML页面本身
- Socket.IO的JavaScript(180千字节)
- 首先长时间轮询AJAX请求
- 第二长轮询AJAX请求
- 第三轮投票AJAX请求
- 连接升级到WebSocket
细节
我在本地主机上得到的WebSocket结果:
我在localhost上得到的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,我相信这是原来的问题。 我希望这可以帮助那里的人…