node.js中的socket.io和websockets有什么区别?它们都是服务器推送技术吗?我感觉到的唯一不同是,
socket.io 允许我通过指定事件名称来发送/发送消息。在 socket.io 的情况下,来自服务器的消息将到达所有客户端,但对于 websockets 中的相同,我被迫保留所有连接的数组并循环通过它以向所有客户端发送消息。
另外,我想知道为什么网络检查器(如 Chrome/firebug/fiddler)无法从服务器捕获这些消息(来自 socket.io/websocket)?
请澄清这一点。
误解
关于 WebSocket 和 Socket.IO 的常见误解很少:
第一个误解是使用 Socket.IO 比使用 WebSocket 容易得多,但事实并非如此。请参阅下面的示例。第二个误解是浏览器没有广泛支持 WebSocket。有关更多信息,请参见下文。第三个误解是 Socket.IO 将连接降级为旧浏览器的后备。它实际上假设浏览器是旧的,并开始与服务器建立 AJAX 连接,稍后在交换一些流量后在支持 WebSocket 的浏览器上升级。详情见下文。
我的实验
我写了一个 npm 模块来演示 WebSocket 和 Socket.IO 之间的区别:
https://www.npmjs.com/package/websocket-vs-socket.io
https://github.com/rsp/node-websocket-vs-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');
来源: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');
来源: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); });
来源: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); });
来源:https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html
网络流量
要查看网络流量的差异,您可以run my test。这是我得到的结果:
WebSocket 结果
个请求,1.50 KB,0.05 秒
从这两个请求中:
HTML页面本身连接升级到WebSocket
(连接升级请求在开发人员工具上可见,并带有 101 Switching Protocols 响应。)
Socket.IO 结果
个请求,181.56 KB,0.25 秒
从这 6 个请求中:
HTML 页面本身 Socket.IO 的 JavaScript (180 KB) 第一次长轮询 AJAX 请求 第二次长轮询 AJAX 请求 第三次长轮询 AJAX 请求 连接升级到 WebSocket
截图
我在 localhost 上得到的 WebSocket 结果:
https://i.stack.imgur.com/e2yY5.png
我在 localhost 上得到的 Socket.IO 结果:
https://i.stack.imgur.com/RHymm.png
测试自己
快速开始:
# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io
在浏览器中打开 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
浏览器兼容性
截至 2016 年 6 月,WebSocket 可在除 Opera Mini 之外的所有设备上运行,包括高于 9 的 IE。
这是截至 2016 年 6 月 Can I Use 上 WebSocket 的浏览器兼容性:
https://i.stack.imgur.com/igTKM.png
有关最新信息,请参阅 http://caniuse.com/websockets。
它的优点是它简化了 WebSockets 的使用,正如您在 #2 中描述的那样,并且可能更重要的是,它提供了在浏览器或服务器不支持 WebSockets 的情况下对其他协议的故障转移。我会避免直接使用 WebSockets,除非您非常熟悉它们不工作的环境并且您能够解决这些限制。
这是一本关于 WebSockets 和 Socket.IO 的好书。
http://davidwalsh.name/websocket
tl;博士;
比较它们就像比较餐厅的食物(有时可能很贵,也许不是 100% 你想要它)与自制食物,你必须自己收集和种植每种成分。
也许如果你只是想吃一个苹果,后者更好。但是如果你想要一些复杂的东西并且你一个人,那真的不值得自己做饭和制作所有的食材。
我已经与这两个工作过。这是我的经验。
套接字IO
有自动连接
有命名空间
有房间
有订阅服务
具有预先设计的通信协议(谈论订阅,取消订阅或向特定房间发送消息的协议,您必须自己在 websockets 中设计它们)
具有良好的日志记录支持
已与redis等服务集成
在不支持 WS 的情况下具有后备功能(不过,这种情况越来越少见)
这是一个图书馆。这意味着,它实际上在各个方面都在帮助您的事业。 Websockets 是一个协议,而不是一个库,SocketIO 无论如何都使用它。
整个架构由不是您的人支持和设计,因此您不必花时间设计和实现上述任何内容,但您可以直接编写业务规则。
有一个社区,因为它是一个库(你不能有一个用于 HTTP 或 Websockets 的社区:P 它们只是标准/协议)
网络套接字
你拥有绝对的控制权,这取决于你是谁,这可能非常好或非常糟糕
它很轻(记住,它是一个协议,而不是一个库)
您设计自己的架构和协议
没有自动连接,如果需要,您可以自己实现
没有订阅服务,你自己设计
没有日志记录,你实现它
没有后备支持
没有房间或命名空间。如果你想要这样的概念,你自己实现它们
不支持任何东西,你将是实现一切的人
您首先必须专注于技术部分并设计进出您的 Websocket 的所有内容
你必须先调试你的设计,这将花费你很长时间
显然,你可以看到我偏向于 SocketIO。我很想这么说,但我真的不是。
我真的在努力不使用 SocketIO。我不想用它。我喜欢设计自己的东西并自己解决自己的问题。
但是如果你想拥有一个业务而不仅仅是一个 1000 行的项目,并且你要选择 Websockets,你将不得不自己实现每一件事。你必须调试一切。您必须制作自己的订阅服务。您自己的协议。你自己的一切。你必须确保一切都非常复杂。而且你会在这个过程中犯很多错误。您将花费大量时间设计和调试所有内容。我做到了,现在仍然这样做。我正在使用 websockets,我在这里的原因是因为对于一个试图为他的初创公司解决业务规则而不是处理 Websocket 设计术语的人来说,它们是难以忍受的。
如果您是单人军队或试图实现复杂功能的小团队,那么为大型应用程序选择 Websocket 并不是一个简单的选择。我在 Websockets 中编写的代码比过去使用 SocketIO 编写的代码还要多,比使用 SocketIO 编写的代码简单十倍。
我要说的是……如果您想要成品和设计,请选择 SocketIO。 (除非您想要功能非常简单的东西)
我将提供一个反对使用 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 模块使用起来非常简单。
使用 Socket.IO 基本上就像使用 jQuery - 你想支持旧版浏览器,你需要编写更少的代码,并且库将提供回退。 Socket.io 使用 websockets 技术(如果可用),如果不可用,则检查可用的最佳通信类型并使用它。
https://socket.io/docs/#What-Socket-IO-is-not(我强调)
什么 Socket.IO 不是 Socket.IO 不是 WebSocket 实现。尽管 Socket.IO 确实尽可能使用 WebSocket 作为传输,但它会为每个数据包添加一些元数据:数据包类型、命名空间和需要消息确认时的数据包 ID。这就是为什么 WebSocket 客户端将无法成功连接到 Socket.IO 服务器,而 Socket.IO 客户端也将无法连接到 WebSocket 服务器。请在此处查看协议规范。 // 警告:客户端将无法连接!常量客户端 = io('ws://echo.websocket.org');
即使现代浏览器现在支持 WebSockets,我认为没有必要抛弃 SocketIO,它仍然在当今的任何项目中占有一席之地。这很容易理解,而且就个人而言,我通过 SocketIO 了解了 WebSockets 的工作原理。
如本主题所述,有大量用于 Angular、React 等的集成库以及用于 TypeScript 和其他编程语言的定义类型。
我要补充的关于 Socket.io 和 WebSockets 之间差异的另一点是,使用 Socket.io 进行集群并不是什么大问题。 Socket.io 提供 Adapters 可用于将其与 Redis 链接以增强可扩展性。例如,您有 ioredis 和 socket.io-redis。
是的,我知道,SocketCluster 存在,但这是题外话。
我想在 2021 年再提供一个答案。socket.io 自 2020 年 9 月以来再次得到积极维护。在 2019 年至 2020 年 8 月(近 2 年)期间,基本上没有任何活动,我原以为该项目可能已经死了。
Socket.io 也发表了一篇文章叫Why Socket.IO in 2020?,除了回退到 HTTP 长轮询,我认为这 2 个特性是 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/了解更多信息。
Socket.IO 使用 WebSocket,当 WebSocket 不可用时,使用回退算法进行实时连接。