1. socket.io允许我通过指定事件名称来发送/发射消息。 2. 在socket.io的情况下,服务器的消息将到达所有客户端,但在websockets的情况下,我被迫保留所有连接的数组并循环遍历以向所有客户端发送消息。
此外, 我想知道为什么Web检查器(如Chrome / Firebug / Fiddler)无法捕获来自服务器的这些消息(从socket.io / websocket)?
请澄清这一点。
关于WebSocket和Socket.IO存在一些常见的误解:
第一个误解是使用Socket.IO比使用WebSocket更容易,但事实并非如此。请参见下面的示例。
第二个误解是WebSocket在浏览器中得不到广泛支持。了解更多信息,请参见下文。
第三个误解是Socket.IO将连接降级为旧浏览器上的备用选项。它实际上假设浏览器较旧,开始与服务器建立AJAX连接,在交换一些流量后在支持WebSocket的浏览器上升级。有关详细信息,请参见下文。
我编写了一个npm模块来演示WebSocket和Socket.IO之间的区别:
这是一个简单的服务器端和客户端代码示例 - 客户端使用WebSocket或Socket.IO连接到服务器,服务器以1秒的时间间隔发送三条消息,由客户端添加到DOM中。
将使用WebSocket和Socket.IO执行相同操作的服务器端示例与Express.js应用程序进行比较:
使用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');
使用 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实现相同功能的示例:
使用原始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); });
使用简单的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
要查看网络流量的差异,您可以运行我的测试。以下是我得到的结果:
从这 2 个请求中:
(连接升级请求可在开发工具中看到 101 Switching Protocols 响应。)
从这 6 个请求中:
我在本地主机上获得的 WebSocket 结果:
我在本地主机上获得的 Socket.IO 结果:
快速启动:
# 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 的浏览器兼容性:
有关最新信息,请参见http://caniuse.com/websockets。
它的优点在于简化了WebSockets的使用,正如您在#2中所描述的那样,并且更重要的是,在浏览器或服务器不支持WebSockets的情况下提供了其他协议的故障转移。除非您非常熟悉它们无法正常工作的环境并且能够克服这些限制,否则我建议避免直接使用WebSockets。
这篇文章对WebSockets和Socket.IO都是一个很好的阅读材料。
简而言之:
将它们进行比较就像是比较餐厅食品(有时可能很昂贵,也可能不完全符合你的要求)和家庭烹饪,在后者中,你必须自己收集和种植每一种原料。
也许如果你只想吃一个苹果,后者更好。但如果你想要复杂的东西并且你是一个人,那么真的不值得自己动手做所有的原料。
我曾经使用过这两个技术。以下是我的经验。
SocketIO
具有自动连接功能
具有命名空间
具有房间
具有订阅服务
具有预设计的通信协议
(指订阅、取消订阅或向特定房间发送消息的协议,你必须在websockets中自己设计它们)
具有良好的日志支持
与redis等服务集成
在WS不受支持的情况下具有回退功能(尽管这种情况越来越少见)
它是一个库。这意味着,它实际上在各个方面都有助于你的事业。Websockets是一种协议,而不是一个库,SocketIO无论如何都使用它。
整个架构是由其他人支持和设计的,因此您不需要花时间从头设计和实现任何内容,而是可以直接编写业务规则。
它有一个社区,因为它是一个库 (你不能为HTTP或Websockets建立社区: P,它们只是标准/协议)
Websockets
显然,您可以看到我对SocketIO有偏见。我很想这样说,但实际上并不是。
我实在很努力地不去使用SocketIO,我不想用它。我喜欢自己设计我的东西并亲自解决问题。
但是,如果你想要一个业务而不仅仅是一个1000行代码的项目,并且你想选择Websockets,那么你就需要自己实现每一件事情。你必须调试所有东西。你必须制作自己的订阅服务、协议、以及其他所有东西。而且你必须确保所有东西都相当精密。你会犯很多错误。你将花费大量时间设计和调试一切。我曾经这样做,现在仍在进行中。 我正在使用Websockets,我之所以在这里是因为对于一个人来说,尝试解决创业公司的业务规则,而不是处理Websocket设计术语,它们非常难以承受。
如果你是一个人或一个小团队,尝试实现复杂的功能,那么选择Websockets并不是一个容易的选择。我在Websockets中编写的代码比我过去在SocketIO中编写的代码还要多,但我的代码只实现了十分简单的功能。
我想说的是...如果你想要一个成品和设计,就选择SocketIO。(除非你只需要非常简单的功能)
我将提出反对使用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模块非常简单易用。
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');
使用redis-adapter,将服务器进程扩展到多个节点很容易,但为ws服务器负载均衡很难。在此处查看 https://socket.io/docs/v4/using-multiple-nodes/ 获取更多信息。
Socket.IO使用WebSocket,当WebSocket不可用时,使用回退算法进行实时连接。
简而言之:
'Socket.io'是一种可以在应用层上实现的规范,它可以在应用层规范“Websockets”的基础上实现。
我认为这里的简单答案在于基本的网络技术定义: