繁体   English   中英

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

[英]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。

如果你想避免从长轮询开始,请参阅arnoldNick Steele的答案。 我将更详细地解释发生了什么。

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

的WebSocket

2个请求,1.50 KB,0.05 s

从这2个请求:

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

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

Socket.IO

6个请求,181.56 KB,0.25 s

从这6个请求中:

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

细节

我在localhost上获得的WebSocket结果:

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

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

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

测试自己

在npmGitHub 发布了代码,你可以自己运行它:

# 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.

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