简体   繁体   English

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

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

We are developing a web application that will run only on modern browsers (IE10+) for different reasons. 我们正在开发一个仅在现代浏览器(IE10 +)上运行的Web应用程序,原因各不相同。

One of the features we implemented is Socket.io 1.x. 我们实现的功能之一是Socket.io 1.x. However, by default the Socket.io client tries to support older browsers, so it starts a connection with long polling and then updates that to WebSockets. 但是,默认情况下,Socket.io客户端会尝试支持较旧的浏览器,因此它会启动与长轮询的连接,然后将其更新到WebSockets。 This is a waste of time and resources, given we know for sure the browser supports WS. 这是浪费时间和资源,因为我们知道浏览器支持WS。

I've searched around, and I can only find this wiki page which, however, is about Socket.io 0.9. 我一直在搜索,我只能找到这个wiki页面 ,但是,它是关于Socket.io 0.9的。

Eventually, I found the documentation for engine.io-client (on which Socket.io-client is based on the 1.x branch). 最后,我找到了engine.io-client的文档 (Socket.io-client基于1.x分支)。 This is the code that I wrote and seems to be working. 这是我编写的代码, 似乎正在运行。 However, I would like to know if it's correct or if I'm doing something wrong: 但是,我想知道它是否正确或者我做错了什么:

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

Weirdly, just setting the transports property to an array with websockets only wasn't enough; 奇怪的是,仅将transports属性设置为仅包含websockets的数组是不够的; I also had to disable upgrade . 我还必须禁用upgrade Is this correct? 它是否正确?

Update 更新

I made some new discoveries. 我做了一些新的发现。

With transports set to ['websocket'] only, it doesn't make any difference wether upgrade is enabled or not. 如果仅将transports设置为['websocket'] ,则无论是否启用upgrade都不会产生任何差异。 Is that normal? 这是正常的吗?

There are two types of "upgrades" happening with socket.io. socket.io发生了两种类型的“升级”。 First (in socket.io 1.0+), socket.io starts all connections with an http polling request and it may actually exchange some initial data with just an http request. 首先(在socket.io 1.0+中),socket.io启动所有与http轮询请求的连接,它实际上可能只用一个http请求交换一些初始数据。 Then, at some point after that, it will try to actually initiate a webSocket connection. 然后,在此之后的某个时刻,它将尝试实际启动webSocket连接。 the webSocket connection is done by sending a particular type of http request that specifies an upgrade: websocket header and the server can then respond appropriately whether it supports websocket or not. webSocket连接通过发送指定upgrade: websocket的特定类型的http请求来完成upgrade: websocket标头,然后服务器可以适当地响应它是否支持websocket。 If the server agrees to the upgrade, then that particular http connection is "upgraded" to the webSocket protocol. 如果服务器同意升级,则该特定http连接被“升级”为webSocket协议。 At that point, the client then knows that webSocket is supported and it stops using the polling http requests, thus completing its upgrade to webSocket. 此时,客户端知道webSocket受支持并且它停止使用轮询http请求,从而完成其upgrade到webSocket。

You can prevent the initial http polling entirely by doing this on the client: 您可以通过在客户端上执行此操作来完全阻止初始http轮询:

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

This will prevent polling connections from your own cooperating clients. 这将阻止来自您自己的合作客户端的轮询连接。 If you want to prevent any clients from ever using polling, then you can add this to the server: 如果要阻止任何客户端使用轮询,则可以将其添加到服务器:

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

But, if you set this on the server, socket.io clients that are initially connecting with http polling will not work at all. 但是,如果在服务器上设置此项,则最初使用http轮询连接的socket.io客户端根本不起作用。 So, this should only be matched with the right settings in the client such that the client never starts with polling. 因此,这应该只与客户端中的正确设置匹配,以便客户端永远不会以轮询开始。

This will tell both ends that you only want to use webSockets and socket.io will skip the extra http polling at the beginning. 这将告诉两端你只想使用webSockets而socket.io将在开头跳过额外的http轮询。 Fair warning, doing this requires webSocket support so this rules out compatible with older versions of IE that didn't yet support webSocket. 公平警告,这样做需要webSocket支持,所以这排除了与尚未支持webSocket的旧版IE兼容。 If you want to retain compatibility, then just let socket.io do it's thing with a couple http requests initially. 如果你想保留兼容性,那么让socket.io最初做几个http请求。


Here's more info on the protocol upgrade from http to webSocket. 以下是从http到webSocket的协议升级的更多信息。

The webSockets protocol initiates EVERY webSocket with an HTTP connection. webSockets协议使用HTTP连接启动每个webSocket。 That's the way all webSockets work. 这就是所有webSockets的工作方式。 That HTTP connection contains some headers on it that indicate that the browser would "like" to upgrade to the webSockets protocol. 该HTTP连接包含一些标题,表明浏览器“喜欢”升级到webSockets协议。 If the server support that protocol, then it responds telling the client that it will upgrade to the webSocket protocol and that very socket then switches from the HTTP protocol to the webSocket protocol. 如果服务器支持该协议,则它会响应告知客户端它将升级到webSocket协议,然后该套接字将从HTTP协议切换到webSocket协议。 This is how a webSocket connection is designed to work. 这就是webSocket连接的设计方式。 So, the fact that you see your webSocket connection starting with an HTTP connection is 100% normal. 因此,您看到以HTTP连接开头的webSocket连接的事实是100%正常。

You can configure socket.io to NEVER use long polling if that makes you feel better, but this will not change the fact that the webSocket connection will still start with an HTTP connection that is then upgraded to the webSocket protocol and it will not improve the efficiency of operation in modern browsers that support webSockets. 您可以将socket.io配置为永远不会使用长轮询,如果这让您感觉更好,但这不会改变webSocket连接仍将以HTTP连接开始,然后升级到webSocket协议并且不会改善支持webSockets的现代浏览器的操作效率。 It will, however make it so that your connection will not work in older browsers. 但是,它会使您的连接无法在旧版浏览器中使用。

To tell Socket.IO to use WebSocket only instead of a few XHR requests first, just add this to the Node server: 要告诉Socket.IO仅使用WebSocket而不是首先使用几个XHR请求,只需将其添加到节点服务器:

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

And on the client add this: 并在客户端添加此:

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

This tells Socket.IO to only use WebSocket protocol and nothing else; 这告诉Socket.IO只使用WebSocket协议而不是别的; it's cleaner, faster and uses a little less resources on the client and server sides. 它更干净,更快,并且在客户端和服务器端使用更少的资源。

Now you'll only see a single WebSocket connection in your network request list, just keep in mind IE9 and earlier can't use WebSocket. 现在,您只会在网络请求列表中看到单个WebSocket连接,请记住IE9及更早版本不能使用WebSocket。

I'm posting that answer because the accepted answer is not correct - it confuses the Socket.IO upgrade from long-polling AJAX to WebSocket with the WSS protocol "Connection: Upgrade" request. 我发布了答案,因为接受的答案是不正确的 - 它将Socket.IO从长轮询AJAX升级到WebSocket与WSS协议“连接:升级”请求混淆。 The issue is not that the WebSocket connection starts as HTTP and gets upgraded to WebSocket - how could it not? 问题不在于WebSocket连接是以HTTP身份启动并升级到WebSocket - 它怎么可能不是? - but that Socket.IO starts with a long-polling AJAX connection even on browsers supporting WebSocket, and only upgrades it later after exchanging some traffic. - 但是,即使在支持WebSocket的浏览器上,Socket.IO也会以长轮询AJAX连接开始,并且只在交换一些流量后才进行升级。 It's very easy to see in the developer tools of Firefox or Chrome. 在Firefox或Chrome的开发者工具中很容易看到。

The author of the question is correct in his observations. 这个问题的作者在他的观察中是正确的。 The "upgrade" in Socket.IO doesn't refer to the HTTP to WSS protocol upgrade as is often misunderstood but to the upgrade of Socket.IO connection from long-polling AJAX connection to WebSocket. Socket.IO中的“升级”并不是指HTTP到WSS协议升级,因为它经常被误解,而是指从长轮询AJAX连接升级到WebSocket的Socket.IO连接。 If you start with WebSocket already (which is not the default) then upgrade false has no effect because you don't need to upgrade. 如果您已经开始使用WebSocket(这不是默认设置),那么升级false无效,因为您不需要升级。 If you start with polling and disable upgrade then it stays that way and doesn't upgrade to WebSocket. 如果您从轮询开始并禁用升级,那么它将保持这种状态,并且不会升级到WebSocket。

See answers by arnold and Nick Steele if you want to avoid starting with long-polling. 如果你想避免从长轮询开始,请参阅arnoldNick Steele的答案。 I will explain what is going on in more detail. 我将更详细地解释发生了什么。

This is what I observed in my experiments with simple WebSocket and Socket.IO apps: 这是我在使用简单的WebSocket和Socket.IO应用程序的实验中观察到的:

WebSocket 的WebSocket

2 requests, 1.50 KB, 0.05 s 2个请求,1.50 KB,0.05 s

From those 2 requests: 从这2个请求:

  1. HTML page itself HTML页面本身
  2. connection upgrade to WebSocket 连接升级到WebSocket

(The connection upgrade request is visible on the developer tools with a 101 Switching Protocols response.) (连接升级请求在具有101个交换协议响应的开发人员工具上可见。)

Socket.IO Socket.IO

6 requests, 181.56 KB, 0.25 s 6个请求,181.56 KB,0.25 s

From those 6 requests: 从这6个请求中:

  1. the HTML page itself HTML页面本身
  2. Socket.IO's JavaScript (180 kilobytes) Socket.IO的JavaScript(180千字节)
  3. first long polling AJAX request 第一次长轮询AJAX请求
  4. second long polling AJAX request 第二次长轮询AJAX请求
  5. third long polling AJAX request 第三次长轮询AJAX请求
  6. connection upgrade to WebSocket 连接升级到WebSocket

Details 细节

WebSocket results that I got on localhost: 我在localhost上获得的WebSocket结果:

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

Socket.IO results that I got on localhost: 我在localhost上得到的Socket.IO结果:

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

Test yourself 测试自己

I published the code on npm and on GitHub , you can run it yourself: 在npmGitHub 发布了代码,你可以自己运行它:

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

and follow instrictions. 并遵循限制。 To uninstall: 要卸载:

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

See this answer for more info. 有关详细信息,请参阅此答案

I thought I should add to the accepted answer above, as if anyone wants to eliminate the XHR Polling transport and initiate websockets right away. 我认为我应该添加上面接受的答案,好像有人想要消除XHR轮询传输并立即启动websockets。 The code below is just to give an idea of the implementation: 下面的代码只是为了说明实现:

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);

    });
});

After the server is setup, you will see this: 设置服务器后,您将看到:

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

If you don't force the transport, you'd see "polling" instead of websocket. 如果你不强制运输,你会看到“轮询”而不是websocket。 However, this doesn't happen on the client side alone, the server must be setup as well: 但是,这不会仅在客户端发生,服务器也必须设置:

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.

Danger 危险

If the client actually does not support the websocket protocol, a connection won't happen and the client will report an xhr poll error . 如果客户端居然支持WebSocket协议,连接不会发生,客户端将报告一个xhr poll error

This is working perfectly for me because I can control the clients I have, so I have the luxury to force websockets right away, which I believe is what the original question is asking. 这对我来说非常合适,因为我可以控制我拥有的客户,因此我可以立即强制使用websockets,我相信这是原始问题所要求的。 I hope this helps someone out there... 我希望这可以帮助那些人......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM