socket.io和websockets之间的区别

687
什么是socket.io和websockets在node.js中的区别? 它们都是服务器推技术吗? 我感受到的唯一差异是,
1. socket.io允许我通过指定事件名称来发送/发射消息。 2. 在socket.io的情况下,服务器的消息将到达所有客户端,但在websockets的情况下,我被迫保留所有连接的数组并循环遍历以向所有客户端发送消息。
此外, 我想知道为什么Web检查器(如Chrome / Firebug / Fiddler)无法捕获来自服务器的这些消息(从socket.io / websocket)?
请澄清这一点。

9
关于为什么 web 工具无法捕获流量,请参考 如何使用 Firebug 或其他工具查看 WS/WSS WebSocket 请求内容? - treaz
1
@treaz,你不需要Firebug或其他任何工具。Chrome的开发者工具在网络选项卡下显示WS连接。 - user4846835
也可以查看这个(不确定是否最新)- https://www.educba.com/websocket-vs-socket-io/ - Manohar Reddy Poreddy
我认为默认的socket.io行为(在服务器端)不会向所有客户端发送消息。我错了吗?我认为socket.emit(event,data)将向特定客户端发送数据,而不是所有客户端。 - basilisk
1
请问有关于Socket.io和RSocket的文档吗? - PatPanda
12个回答

824

误解

关于WebSocket和Socket.IO存在一些常见的误解:

  1. 第一个误解是使用Socket.IO比使用WebSocket更容易,但事实并非如此。请参见下面的示例。

  2. 第二个误解是WebSocket在浏览器中得不到广泛支持。了解更多信息,请参见下文。

  3. 第三个误解是Socket.IO将连接降级为旧浏览器上的备用选项。它实际上假设浏览器较旧,开始与服务器建立AJAX连接,在交换一些流量后在支持WebSocket的浏览器上升级。有关详细信息,请参见下文。

我的实验

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

这是一个简单的服务器端和客户端代码示例 - 客户端使用WebSocket或Socket.IO连接到服务器,服务器以1秒的时间间隔发送三条消息,由客户端添加到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');

Socket.IO 服务器

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

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

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

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

客户端

比较在浏览器中使用WebSocket和Socket.IO实现相同功能的示例:

WebSocket客户端

使用原始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); });

Socket.IO客户端

使用简单的JavaScript代码实现的Socket.IO客户端示例:

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

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

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

网络流量

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

WebSocket 结果

2 个请求,1.50 KB,0.05 秒

从这 2 个请求中:

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

(连接升级请求可在开发工具中看到 101 Switching Protocols 响应。)

Socket.IO 结果

6 个请求,181.56 KB,0.25 秒

从这 6 个请求中:

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

截图

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

WebSocket results - websocket-vs-socket.io module

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

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

自行测试

快速启动:

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

在浏览器中输入http://localhost:3001/,通过Shift+Ctrl+I打开开发者工具,在Network标签下按Ctrl+R重新加载页面以查看WebSocket版本的网络流量。

在浏览器中输入http://localhost:3002/,通过Shift+Ctrl+I打开开发者工具,在Network标签下按Ctrl+R重新加载页面以查看Socket.IO版本的网络流量。

卸载方式:

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

浏览器兼容性

截至2016年6月,WebSocket 在除 Opera Mini 以外的所有浏览器上都可以使用,包括IE9及以上版本。

以下是2016年6月在 Can I Use 上 WebSocket 的浏览器兼容性:

enter image description here

有关最新信息,请参见http://caniuse.com/websockets


54
你的意思是websocket比socket.io更好? - Jack Moscovi
84
@JackMoscovi 我不会说 WebSocket 一定更好。这取决于需求。WebSocket 的优势在于它是一个 Web 标准(最初由 W3C 和 whatwg 开发,现在由 IETF 推广并发表了一份 RFC,已经有五年了),由于浏览器本身的支持,所以非常轻便,但是浏览器的支持并不普遍。Socket.IO 支持更多的浏览器并且带有更多功能,但也伴随着一些额外开销。有时候 WebSocket 更好,有时候 Socket.IO 更好,就像选择 querySelectorAll 和 jQuery 一样,答案并不总是相同的。 - rsp
31
这里的回答很棒!!在许多情况下,似乎socket.io已经不再必要... 也可以看看这篇好文章!https://medium.com/@ivanderbyl/why-you-don-t-need-socket-io-6848f1c871cd#.ne0k4uegk - Alvaro
56
非常好的比较。然而,值得注意的是,Socket.io添加了房间名称空间、大量连接细节和日志细节,还有很多与Angular、Vue、React等集成库的整合。最重要的是,你可以禁用Ajax长轮询,直接通过WebSocket连接,就像原始的WebSocket连接一样。这样,除了180kb的库之外,你可以获得所有东西。直接使用WebSocket是比较繁琐的,除非你只需要最基本的东西。对于企业来说,放弃房间和访问社区IP是令人生畏的。 - Nick Steele
17
SocketIO 比 Websockets 更容易。原文作者编写了一些利用 SocketIO 特性的代码,这些特性在 Websockets 代码中无法复制,例如 rooms 和 subs。SocketIO 提供了协议和订阅服务,而 Websocket 强制你自己设计架构和协议。这意味着你需要写十倍于 Websockets 的代码,并且需要花费 x100 的时间来设计架构和调试每一个错误(相信我,这就是为什么我正在重新审视我的决定)。SocketIO 不仅是为了支持旧版本浏览器,它也更加容易使用。 - Eksapsy
显示剩余2条评论

410

它的优点在于简化了WebSockets的使用,正如您在#2中所描述的那样,并且更重要的是,在浏览器或服务器不支持WebSockets的情况下提供了其他协议的故障转移。除非您非常熟悉它们无法正常工作的环境并且能够克服这些限制,否则我建议避免直接使用WebSockets。

这篇文章对WebSockets和Socket.IO都是一个很好的阅读材料。

http://davidwalsh.name/websocket


85
Socket.IO并非建立在WebSockets之上,只是在可用时使用该技术。 - moka
31
语义差异,我在答案的其余部分进行了解释,但我已更新答案以反映这一点。 - Timothy Strimple
2
@moka,从你的话中可以得出以下结论吗?下面这个语句是错误的吗?Socket.IO 实际上不仅仅是 WebSockets 的一层。 - Pulak Kanti Bhattacharyya
4
请问您具体指的是哪个陈述?Socket.IO不仅仅是WebSocket上面的一层,它具有不同的语义(可以为消息打上名称),并且可以故障转移到不同的协议,同时还具有心跳机制。另外,它还会在服务器端附加客户端ID等。因此,它不只是一个包装器,而是一个功能齐全的库。 实际上,Socket.IO近年来得到的支持不好,因此我建议使用SockJS作为更好、更维护的Socket.IO替代品。 - moka
5
一个月前,我可能会同意你的观点。但是现在 Socket.io 1.0 已经发布并且正在接受更新。 - Timothy Strimple
显示剩余6条评论

105

简而言之:

将它们进行比较就像是比较餐厅食品(有时可能很昂贵,也可能不完全符合你的要求)和家庭烹饪,在后者中,你必须自己收集和种植每一种原料。

也许如果你只想吃一个苹果,后者更好。但如果你想要复杂的东西并且你是一个人,那么真的不值得自己动手做所有的原料。


我曾经使用过这两个技术。以下是我的经验。

SocketIO

  • 具有自动连接功能

  • 具有命名空间

  • 具有房间

  • 具有订阅服务

  • 具有预设计的通信协议

    (指订阅、取消订阅或向特定房间发送消息的协议,你必须在websockets中自己设计它们)

  • 具有良好的日志支持

  • 与redis等服务集成

  • 在WS不受支持的情况下具有回退功能(尽管这种情况越来越少见)

  • 它是一个库。这意味着,它实际上在各个方面都有助于你的事业。Websockets是一种协议,而不是一个库,SocketIO无论如何都使用它。

  • 整个架构是由其他人支持和设计的,因此您不需要花时间从头设计和实现任何内容,而是可以直接编写业务规则。

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

  • Websockets

    • 根据您的身份,您拥有绝对的控制权,这可能非常好,也可能非常糟糕
    • 它是最轻量级的(记住,它是一个协议,而不是库)
    • 您可以设计自己的架构和协议
    • 它没有自动连接功能,如果您想要它,您需要自己实现
    • 它没有订阅服务,您需要自行设计
    • 它没有日志记录,您需要自己实现
    • 它没有后备支持
    • 它没有房间或命名空间。如果您想要这样的概念,您需要自行实现
    • 它没有任何支持,您将成为实现所有功能的人
    • 您首先必须专注于技术部分,并设计Websockets来回传递的所有内容
    • 您必须先调试设计,这将花费很长时间

    显然,您可以看到我对SocketIO有偏见。我很想这样说,但实际上并不是。

    我实在很努力地不去使用SocketIO,我不想用它。我喜欢自己设计我的东西并亲自解决问题。

    但是,如果你想要一个业务而不仅仅是一个1000行代码的项目,并且你想选择Websockets,那么你就需要自己实现每一件事情。你必须调试所有东西。你必须制作自己的订阅服务、协议、以及其他所有东西。而且你必须确保所有东西都相当精密。你会犯很多错误。你将花费大量时间设计和调试一切。我曾经这样做,现在仍在进行中。 我正在使用Websockets,我之所以在这里是因为对于一个人来说,尝试解决创业公司的业务规则,而不是处理Websocket设计术语,它们非常难以承受。

    如果你是一个人或一个小团队,尝试实现复杂的功能,那么选择Websockets并不是一个容易的选择。我在Websockets中编写的代码比我过去在SocketIO中编写的代码还要多,但我的代码只实现了十分简单的功能。

    我想说的是...如果你想要一个成品和设计,就选择SocketIO。(除非你只需要非常简单的功能)


    46

    我将提出反对使用socket.io的论点。

    我认为仅仅因为socket.io具有回退功能而使用它并不是一个好主意。让IE8成为过去吧。

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

    如果您要开发针对Android应用程序或其他需要与现有应用程序一起工作的内容,那么直接使用WS可能更好,socket.io可能会给您带来一些麻烦...

    此外,Node.JS的WS模块非常简单易用。


    40
    使用 Socket.IO 基本上就像使用 jQuery 一样 - 如果想要支持旧版浏览器,你需要写更少的代码,而库会提供兼容性。如果有可用的 WebSockets 技术,Socket.io 将使用它,否则会检查最佳通信类型并使用它。

    3
    据我所知,我认为这个例子有点不好,因为jQuery不支持旧版浏览器。这会给新手留下印象,现在应该使用jQuery。如果您使用最新的ECMAs,则可以使用Babel解决这个问题。:D 请原谅我的吹毛求疵,我经常看到新手无缘无故地使用jQuery,因为他们在学习JavaScript之前就学习了jQuery,我只是想减少这种不良实践现象的贡献者。 - Eksapsy
    5
    jQuery最初的目的是良好地支持浏览器不兼容性。如果你看一下我的回答日期,就会明白。当然,由于现在浏览器不再存在不兼容性,它已经过时了。 - Dev Agrawal

    24

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

    9
    我想在2021年再提供一个答案。自2020年9月以来,socket.io再次得到积极维护。在2019年至2020年8月(近两年)期间,基本上没有任何活动,我曾认为该项目可能已经停止。
    Socket.io还发表了一篇名为“为什么在2020年选择Socket.IO?”的文章,除了回退到HTTP长轮询外,我认为这两个功能是socket.io提供的,websocket缺乏的:
    - 自动重新连接 - 将数据广播到给定客户端集合的方法(房间/命名空间)
    我发现socket.io还有一个方便的功能,用于ws服务器开发,特别是我使用docker进行服务器部署。因为我总是启动多个服务器实例,所以跨ws服务器通信是必须的,而socket.io为此提供了https://socket.io/docs/v4/redis-adapter/

    使用redis-adapter,将服务器进程扩展到多个节点很容易,但为ws服务器负载均衡很难。在此处查看 https://socket.io/docs/v4/using-multiple-nodes/ 获取更多信息。


    8
    即使现代浏览器现在支持WebSockets,我认为没有必要放弃SocketIO,它仍然在任何现今的项目中都有其存在之处。它易于理解,并且个人而言,我通过SocketIO学习了WebSockets的工作原理。
    如本主题所述,对于Angular、React等,有大量的集成库和TypeScript和其他编程语言的定义类型。
    我想要补充关于Socket.io和WebSockets之间差异的另一点是,使用Socket.io进行集群不是一件大事。Socket.io提供适配器,可以用于将其与Redis连接以增强可扩展性。例如,您可以使用ioredissocket.io-redis
    是的,我知道SocketCluster存在,但那是离题了。

    4

    Socket.IO使用WebSocket,当WebSocket不可用时,使用回退算法进行实时连接。


    1

    简而言之:

    'Socket.io'是一种可以在应用层上实现的规范,它可以在应用层规范“Websockets”的基础上实现。

    websocket规范
    socket.io规范

    我认为这里的简单答案在于基本的网络技术定义:

    1. 规范:详细记录了程序需要满足的标准以被标记为“某些规范的实现”。在构建程序时获得这个认证非常重要,因为任何程序只能在执行代码的机器上运行。编程基本上是建立在规范之上的,如果不遵循规范,代码将无法正确执行。然而,规范本身并没有起到任何作用。它只是一个文本文件。
    2. 实现:这是实际可执行的代码,完成规范所述的任务。
    3. 应用层 - 定义在传输过程中发送的消息和握手的系统。这是你在使用HTTP/Websockets/Socketio时必须了解的内容。它定义了如何建立连接、进行身份验证、发送数据以及如何接收数据。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接