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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28238628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:26:20  来源:igfitidea点击:

Socket.io 1.x: use WebSockets only?

javascriptwebsocketsocket.io

提问by ItalyPaleAle

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. 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. This is a waste of time and resources, given we know for sure the browser supports WS.

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

I've searched around, and I can only find this wiki pagewhich, 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). This is the code that I wrote and seemsto be working. However, I would like to know if it's correct or if I'm doing something wrong:

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

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

Weirdly, just setting the transportsproperty to an array with websocketsonly wasn't enough; I also had to disable upgrade. Is this correct?

奇怪的是,仅仅将transports属性设置为一个数组websockets是不够的;我也不得不禁用upgrade. 这样对吗?

Update

更新

I made some new discoveries.

我有了一些新的发现。

With transportsset to ['websocket']only, it doesn't make any difference wether upgradeis enabled or not. Is that normal?

随着transports设置为['websocket']只,它没有任何阉差upgrade被启用。这是正常的吗?

回答by jfriend00

There are two types of "upgrades" happening with 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. Then, at some point after that, it will try to actually initiate a webSocket connection. the webSocket connection is done by sending a particular type of http request that specifies an upgrade: websocketheader and the server can then respond appropriately whether it supports websocket or not. If the server agrees to the upgrade, then that particular http connection is "upgraded" to the webSocket protocol. At that point, the client then knows that webSocket is supported and it stops using the polling http requests, thus completing its upgradeto webSocket.

socket.io 有两种类型的“升级”。首先(在 socket.io 1.0+ 中),socket.io 用一个 http 轮询请求启动所有连接,它实际上可能只用一个 http 请求交换一些初始数据。然后,在此之后的某个时刻,它将尝试实际启动 webSocket 连接。webSocket 连接是通过发送特定类型的 http 请求来完成的,该请求指定了一个upgrade: websocket标头,然后服务器可以适当地响应它是否支持 websocket。如果服务器同意升级,则该特定 http 连接将“升级”为 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. So, this should only be matched with the right settings in the client such that the client never starts with polling.

但是,如果您在服务器上设置它,最初使用 http 轮询连接的 socket.io 客户端将根本无法工作。因此,这应该只与客户端中的正确设置相匹配,以便客户端永远不会开始轮询。

This will tell both ends that you only want to use webSockets and socket.io will skip the extra http polling at the beginning. Fair warning, doing this requires webSocket support so this rules out compatible with older versions of IE that didn't yet support webSocket. If you want to retain compatibility, then just let socket.io do it's thing with a couple http requests initially.

这将告诉两端您只想使用 webSockets 并且 socket.io 将跳过开始时额外的 http 轮询。公平警告,这样做需要 webSocket 支持,因此这排除了与尚不支持 webSocket 的旧版本 IE 兼容的可能性。如果你想保持兼容性,那么最初只让 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. That's the way all webSockets work. That HTTP connection contains some headers on it that indicate that the browser would "like" to upgrade to the webSockets protocol. 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. This is how a webSocket connection is designed to work. So, the fact that you see your webSocket connection starting with an HTTP connection is 100% normal.

webSockets 协议通过 HTTP 连接启动每个 webSocket。这就是所有 webSockets 的工作方式。该 HTTP 连接包含一些标头,表明浏览器“想要”升级到 webSockets 协议。如果服务器支持该协议,则它会响应告诉客户端它将升级到 webSocket 协议,并且该套接字然后从 HTTP 协议切换到 webSocket 协议。这就是 webSocket 连接的工作原理。因此,您看到以 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. It will, however make it so that your connection will not work in older browsers.

如果这让您感觉更好,您可以将 socket.io 配置为从不使用长轮询,但这不会改变 webSocket 连接仍以 HTTP 连接开始的事实,然后将其升级为 webSocket 协议,并且不会改善在支持 webSockets 的现代浏览器中的操作效率。但是,它会使您的连接无法在较旧的浏览器中工作。

回答by Nick Steele

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 请求,只需将其添加到 Node 服务器:

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; it's cleaner, faster and uses a little less resources on the client and server sides.

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

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。

回答by rsp

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. The issue is not that the WebSocket connection starts as HTTP and gets upgraded to WebSocket - how could it not? - 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. It's very easy to see in the developer tools of Firefox or Chrome.

我发布该答案是因为接受的答案不正确 - 它混淆了从长轮询 AJAX 到 WebSocket 的 Socket.IO 升级与 WSS 协议“连接:升级”请求。问题不在于 WebSocket 连接作为 HTTP 启动并升级为 WebSocket - 怎么可能呢?- 但即使在支持 WebSocket 的浏览器上,Socket.IO 也以长轮询 AJAX 连接开始,并且仅在交换了一些流量后才对其进行升级。在 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. If you start with WebSocket already (which is not the default) then upgrade false has no effect because you don't need to upgrade. If you start with polling and disable upgrade then it stays that way and doesn't upgrade to WebSocket.

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

See answers by arnoldand Nick Steeleif you want to avoid starting with long-polling. I will explain what is going on in more detail.

如果您想避免从长轮询开始,请参阅arnoldNick Steele 的回答。我将更详细地解释正在发生的事情。

This is what I observed in my experimentswith simple WebSocket and Socket.IO apps:

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

WebSocket

网络套接字

2 requests, 1.50 KB, 0.05 s

2 个请求,1.50 KB,0.05 秒

From those 2 requests:

从这两个请求中:

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

(The connection upgrade request is visible on the developer tools with a 101 Switching Protocols response.)

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

Socket.IO

套接字接口

6 requests, 181.56 KB, 0.25 s

6 个请求,181.56 KB,0.25 秒

From those 6 requests:

从这 6 个请求中:

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

Details

细节

WebSocket results that I got on localhost:

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

WebSocket results - websocket-vs-socket.io module

WebSocket results - websocket-vs-socket.io module

Socket.IO results that I got on localhost:

我在本地主机上得到的 Socket.IO 结果:

Socket.IO results - websocket-vs-socket.io module

Socket.IO results - websocket-vs-socket.io module

Test yourself

测试自己

I published the code on npmand 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 answerfor more info.

有关更多信息,请参阅此答案

回答by arnold

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. The code below is just to give an idea of the implementation:

我想我应该添加到上面接受的答案中,好像有人想消除 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);

    });
});

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. However, this doesn't happen on the client side alone, the server must be setup as well:

如果您不强制传输,您会看到“轮询”而不是 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.

Danger

危险

If the client actually does notsupport 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. I hope this helps someone out there...

这对我来说非常有效,因为我可以控制我拥有的客户端,所以我可以立即强制使用 websocket,我相信这就是最初的问题。我希望这可以帮助那里的人...