socket.io和websockets之间的差异

Viv*_*vek 403 firebug google-chrome websocket node.js socket.io

node.js中socket.io和websockets之间有什么区别?
它们都是服务器推送技术吗?我觉得唯一的区别是,

  1. socket.io允许我通过指定事件名称来发送/发送消息.

  2. 在socket.io的情况下,来自服务器的消息将到达所有客户端,但对于websockets中的相同内容,我被迫保留所有连接的数组并循环通过它以向所有客户端发送消息.

另外,我想知道为什么网络检查员(如Chrome/firebug/fiddler)无法从服务器捕获这些消息(来自socket.io/websocket)?

请澄清一下.

rsp*_*rsp 454

误区

关于WebSocket和Socket.IO几乎没有什么误解:

  1. 第一个误解是使用Socket.IO比使用WebSocket要容易得多,而WebSocket似乎并非如此.见下面的例子.

  2. 第二个误解是WebSocket在浏览器中没有得到广泛支持.有关详细信息,请参见下文

  3. 第三个误解是Socket.IO将连接降级为旧浏览器的后备.它实际上假设浏览器是旧的并且启动与服务器的AJAX连接,稍后在交换一些流量之后在支持WebSocket的浏览器上升级.请参阅下文了解详情.

我的实验

我写了一个npm模块来演示WebSocket和Socket.IO之间的区别:

它是服务器端和客户端代码的简单示例 - 客户端使用WebSocket或Socket.IO连接到服务器,服务器以1s间隔发送三条消息,由客户端添加到DOM.

服务器端

比较使用WebSocket和Socket.IO的服务器端示例在Express.js应用程序中执行相同操作:

WebSocket服务器

使用Express.js的WebSocket服务器示例:

var path = require('path');
var app = require('express')();
var ws = require('express-ws')(app);
app.get('/', (req, res) => {
  console.error('express connection');
  res.sendFile(path.join(__dirname, 'ws.html'));
});
app.ws('/', (s, req) => {
  console.error('websocket connection');
  for (var t = 0; t < 3; t++)
    setTimeout(() => s.send('message from server', ()=>{}), 1000*t);
});
app.listen(3001, () => console.error('listening on http://localhost:3001/'));
console.error('websocket example');
Run Code Online (Sandbox Code Playgroud)

资料来源:https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.js

Socket.IO服务器

使用Express.js的Socket.IO服务器示例:

var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
  console.error('express connection');
  res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
  console.error('socket.io connection');
  for (var t = 0; t < 3; t++)
    setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
console.error('socket.io example');
Run Code Online (Sandbox Code Playgroud)

资料来源:https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.js

客户端

比较使用WebSocket和Socket.IO的客户端示例在浏览器中执行相同操作:

WebSocket客户端

使用vanilla JavaScript的WebSocket客户端示例:

var l = document.getElementById('l');
var log = function (m) {
    var i = document.createElement('li');
    i.innerText = new Date().toISOString()+' '+m;
    l.appendChild(i);
}
log('opening websocket connection');
var s = new WebSocket('ws://'+window.location.host+'/');
s.addEventListener('error', function (m) { log("error"); });
s.addEventListener('open', function (m) { log("websocket connection open"); });
s.addEventListener('message', function (m) { log(m.data); });
Run Code Online (Sandbox Code Playgroud)

资料来源:https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.html

Socket.IO客户端

使用vanilla JavaScript的Socket.IO客户端示例:

var l = document.getElementById('l');
var log = function (m) {
    var i = document.createElement('li');
    i.innerText = new Date().toISOString()+' '+m;
    l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });
Run Code Online (Sandbox Code Playgroud)

资料来源:https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html

网络流量

要查看网络流量的差异,您可以运行我的测试.以下是我得到的结果:

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模块

测试自己

快速开始:

# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io
Run Code Online (Sandbox Code Playgroud)

在浏览器中打开http:// localhost:3001 /,使用Shift + Ctrl + I打开开发人员工具,打开"网络"选项卡,然后使用Ctrl + R重新加载页面以查看WebSocket版本的网络流量.

在浏览器中打开http:// localhost:3002 /,使用Shift + Ctrl + I打开开发人员工具,打开"网络"选项卡,然后使用Ctrl + R重新加载页面以查看Socket.IO版本的网络流量.

要卸载:

# Uninstall:
npm rm -g websocket-vs-socket.io
Run Code Online (Sandbox Code Playgroud)

浏览器兼容性

截至2016年6月,WebSocket适用于除Opera Mini之外的所有内容,包括高于9的IE.

这是可以在2016年6月使用的WebSocket的浏览器兼容性:

在此输入图像描述

有关最新信息,请访问http://caniuse.com/websockets.

  • @JackMoscovi我不会说WebSocket必然更好.这一切都取决于要求.WebSocket的优点是它是一个Web标准(首先在W3C和whatwg下,现在在IETF下,在5年前发布了RFC),它非常轻量级,因为它本身支持浏览器,但浏览器支持虽然好,但是不普遍.Socket.IO支持更多浏览器并具有更多功能,但也带来一些开销.有时一个更好,有时另一个.这就像在querySelectorAll和jQuery之间进行选择一样 - 答案并不总是一样的 (35认同)
  • 很好的比较.但是,值得注意的是Socket.io增加了房间名称间距,大量的连接细节,大量的日志记录细节,并且Socket.IO有很多集成库,包括Angular,Vue,React等.最重要的是,您可以禁用Ajax长轮询并通过WebSocket直接连接,就像原始WebSocket连接一样.通过这种方式,您可以获得除180kb库之外的所有内容.直接使用WebSocket是痛苦的,除非你只需要最低限度.放弃房间和访问社区IP对企业来说是艰巨的. (21认同)
  • 这里很棒的答案!! 在我看来socket.io在许多情况下不再需要了......看到这篇伟大的文章吧!https://medium.com/@ivanderbyl/why-you-don-t-need-socket-io-6848f1c871cd#.ne0k4uegk (16认同)
  • 所以基本上你说的是,websocket比socket.io好吗? (13认同)
  • @rsp我不认为这些例子在功能上是等价的吗?Socket-io处理中断时自动重新连接(这种情况发生在移动设备上),我认为有些安全问题需要解决吗?您的普通WS示例虽然功能相同,但没有这些属性. (4认同)
  • SocketIO **实际上**比 websockets 更容易。OP 编写的代码利用了一些 SocketIO 的功能,但他没有用 Websockets 的代码复制这些功能,例如 **rooms** 和 subs。SocketIO 为您提供协议和订阅服务。而Websocket则迫使你制定自己的架构和协议。这意味着您必须使用 Websockets 编写 10 倍以上的代码,并且您必须花费 100 倍的时间来设计架构并调试您所犯的每个错误(相信我,这就是我在这里重新调查我的决定的原因)。SocketIO 不仅是为了支持旧版浏览器,而且还更简单 (2认同)

Tim*_*ple 307

它的优点是它简化了#2中描述的WebSockets的使用,并且可能更重要的是,它在浏览器或服务器不支持WebSockets的情况下为其他协议提供故障转移.我会避免直接使用WebSockets,除非您非常熟悉它们不起作用的环境并且您能够解决这些限制.

这是对WebSockets和Socket.IO的良好读取.

http://davidwalsh.name/websocket

  • Socket.IO不是建立在WebSockets之上,只是在它可用时才使用这项技术. (58认同)
  • 语义差异和我在答案的其余部分解释了,但我已经更新了答案以反映这一点. (23认同)
  • @moka一个月前我会同意你的意见.Socket.io 1.0现在已经发布并正在获取更新. (4认同)
  • @PulakKantiBhattacharyya你可以指出你指的是哪个陈述?Socket.IO不仅仅是WebSockets上面的一层,它具有不同的语义(标记带有名称的消息),并且可以故障转移到不同的协议,还有心跳机制.更多内容将ID附加到服务器端的客户端等等.所以它不仅仅是一个包装器,它是功能齐全的库.事实上,近年来它并没有得到很好的支持,所以我建议使用SockJS,它更好,更维护Socket.IO的替代品. (3认同)
  • @moka,从你的话我可以得出以下结论是错误的吗?Socket.IO 实际上不仅仅是 WebSocket 之上的一层。 (2认同)

Eks*_*psy 33

tl;博士;

比较它们就像比较餐厅的食物(有时可能很贵,而且可能不是 100% 你想要的)和自制食物,你必须自己收集和种植每一种成分。

也许如果你只想吃一个苹果,后者更好。但是如果你想要一些复杂的东西并且你一个人,那么你自己烹饪和制作所有食材真的不值得。


我已经和这两个一起工作了。这是我的经验。

套接字IO

  • 有自动连接

  • 有命名空间

  • 有房间

  • 有订阅服务

  • 具有预先设计的通信协议

    (关于订阅、取消订阅或向特定房间发送消息的协议,您必须全部在 websockets 中自己设计)

  • 有很好的日志支持

  • 已与 redis 等服务集成

  • 在不支持 WS 的情况下有后备(不过,这种情况越来越少)

  • 这是一个图书馆。这意味着,它实际上在各个方面都在帮助您的事业。Websockets 是一个协议,而不是一个库,SocketIO 无论如何都会使用它。

  • 整个架构由不是您的人支持和设计,因此您不必花时间设计和实现上述任何内容,但您可以直接编写业务规则。

  • 有一个社区,因为它是一个库(你不能有一个 HTTP 或 Websockets 的社区:P 它们只是标准/协议)

网络套接字

  • 你拥有绝对的控制权,这取决于你是谁,这可能非常好也可能非常糟糕
  • 它尽可能轻巧(请记住,它是一个协议,而不是一个库)
  • 您设计自己的架构和协议
  • 没有自动连接,如果你想要它你自己实现它
  • 没有订阅服务,你来设计
  • 没有日志,你实现它
  • 没有后备支持
  • 没有房间或命名空间。如果你想要这样的概念,你自己实现它们
  • 没有任何支持,你将是实施一切的人
  • 您首先必须专注于技术部分并设计进出您的 Websocket 的所有内容
  • 您必须首先调试您的设计,这将花费您很长时间

显然,你可以看到我偏向于 SocketIO。我很想这么说,但我真的不是。

我真的在争取不使用 SocketIO。我不想使用它。我喜欢设计自己的东西,自己解决自己的问题。但是,如果您想拥有一项业务而不仅仅是一个 1000 行的项目,并且您将选择 Websockets,那么您将不得不自己实现每一件事。你必须调试一切。您必须制作自己的订阅服务。你自己的协议。你自己的一切。而且你必须确保一切都非常复杂。一路上你会犯很多错误。您将花费大量时间设计和调试所有内容。我做到了,现在仍然如此。我正在使用网络套接字 我在这里的原因是因为对于一个试图为他的初创公司解决业务规则而不是处理 Websocket 设计术语的人来说,他们是无法忍受的。

如果您是一个单人军队或一个小团队,为大型应用程序选择 Websockets 并不是一个简单的选择。我在 Websockets 中编写的代码比过去使用 SocketIO 编写的代码要多,我要说的是……如果您想要成品和设计,请选择 SocketIO。(除非你想要一些功能非常简单的东西)


Vic*_*rra 27

我将提供反对使用socket.io的论据.

我认为使用socket.io只是因为它有后备不是一个好主意.让IE8 RIP.

在过去,很多情况下NodeJS的新版本已经破坏了socket.io.您可以查看这些列表以获取示例... https://github.com/socketio/socket.io/issues?q=install+error

如果你去开发Android应用程序或需要使用现有应用程序的东西,你可能会马上使用WS,socket.io可能会给你带来一些麻烦......

此外,Node.JS的WS模块使用起来非常简单.


Dev*_*wal 19

使用Socket.IO基本上就像使用jQuery - 你想支持旧版浏览器,你需要编写更少的代码,库将提供回退.Socket.io使用websockets技术(如果可用),如果没有,则检查可用的最佳通信类型并使用它.

  • 很好地支持浏览器的不一致是 jQuery 的最初目的。如果你看看我的答案上的日期,你就会明白。当然,它并没有过时,因为现在浏览器不一致已经不存在了。 (4认同)
  • 据我所知,我认为这是一个有点糟糕的例子,因为 jQuery 不支持旧版浏览器。这给新手的印象是现在应该使用 jQuery。如果您使用最新的 ECMA,可以使用 babel 来实现此目的。:D 请原谅我的吹毛求疵,我只是看到新手总是无缘无故地使用 jQuery,因为他们在 javascript 之前学习 jquery,我只是想为减少这种不良做法现象做出贡献。 (2认同)

Ken*_*Lin 10

https://socket.io/docs/#What-Socket-IO-is-not重点是

Socket.IO 不是什么

Socket.IO不是WebSocket 实现。尽管 Socket.IO 确实在可能的情况下使用 WebSocket 作为传输,但它为每个数据包添加了一些元数据:数据包类型、命名空间和需要消息确认时的数据包 ID。这就是为什么WebSocket 客户端将无法成功连接到 Socket.IO 服务器,并且Socket.IO 客户端也无法连接到 WebSocket 服务器的原因。请在此处查看协议规范。

// WARNING: the client will NOT be able to connect!
const client = io('ws://echo.websocket.org');
Run Code Online (Sandbox Code Playgroud)


Qiu*_*ang 9

我想在 2021 年再提供一个答案。自 2020 年 9 月以来,socket.io 再次得到积极维护。在 2019 年至 2020 年 8 月(几乎两年)期间,基本上没有任何活动,我原以为该项目可能已经死亡。

Socket.io 还发表了一篇文章《Why Socket.IO in 2020?》,除了 HTTP 长轮询的回退之外,我认为这两个功能是 socket.io 提供而 websocket 缺乏的

  • 自动重连
  • 一种向给定的一组客户端(房间/命名空间)广播数据的方法

我发现 socket.io 的另一项方便功能是用于 ws 服务器开发,特别是我使用 docker 进行服务器部署。因为我总是启动超过 1 个服务器实例,所以跨 ws 服务器通信是必须的,socket.io为其提供了https://socket.io/docs/v4/redis-adapter/ 。

使用redis-adapter,将服务器进程扩展到多个节点很容易,但ws服务器的负载平衡却很困难。请查看此处https://socket.io/docs/v4/using-multiple-nodes/了解更多信息。


Max*_*rie 8

即使现代浏览器现在支持 WebSockets,我认为也没有必要抛弃 SocketIO,它在当今的任何项目中仍然占有一席之地。它很容易理解,就我个人而言,我通过 SocketIO 了解了 WebSocket 的工作原理。

正如本主题中所述,有大量针对 Angular、React 等的集成库以及针对 TypeScript 和其他编程语言的定义类型。

我要补充的另一点是,Socket.io 和 WebSockets 之间的差异是,使用 Socket.io 进行集群并不是什么大问题。Socket.io 提供了适配器,可用于将其与 Redis 链接以增强可扩展性。例如,您有ioredissocket.io-redis 。

是的,我知道,SocketCluster存在,但那是题外话。