误解
关于 WebSocket 和 Socket.IO 的常见误解很少:
第一个误解是使用 Socket.IO 比使用 WebSocket 容易得多,但事实并非如此。请参阅下面的示例。
第二个误解是浏览器没有广泛支持 WebSocket。有关更多信息,请参见下文。
第三个误解是 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');
来源: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
网络流量
要查看网络流量的差异,您可以运行我的测试。这是我得到的结果:
WebSocket 结果
2 个请求,1.50 KB,0.05 秒
从这两个请求中:
- HTML 页面本身
- 连接升级到 WebSocket
(连接升级请求在开发人员工具上可见,并带有 101 Switching Protocols 响应。)
Socket.IO 结果
6 个请求,181.56 KB,0.25 秒
从这 6 个请求中:
- HTML 页面本身
- Socket.IO 的 JavaScript(180 KB)
- 第一个长轮询 AJAX 请求
- 第二个长轮询 AJAX 请求
- 第三次长轮询 AJAX 请求
- 连接升级到 WebSocket
截图
我在 localhost 上得到的 WebSocket 结果:
我在 localhost 上得到的 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 之外的所有设备上运行,包括高于 9 的 IE。
这是截至 2016 年 6 月在Can I Use上 WebSocket 的浏览器兼容性:
有关最新信息,请参阅http://caniuse.com/websockets 。