WebSocket 和 Socket.IO 有什么区别?一文讲述它们之间的差异

本文讲述WebSocket 和 Socket.IO 两者的差异

用 Apifox,节省研发团队的每一分钟

WebSocket 和 Socket.IO 有什么区别?一文讲述它们之间的差异

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录
原文链接:https://medium.com/itnext/differences-between-websockets-and-socket-io-a9e5fa29d3dc   作者:Michele Riva

WebSockets 和 Socket.IO 可能是现代网络中实现实时通信的两种最流行的解决方案。但它们有何不同呢?

讲述WebSocket 和 Socket.IO 两者的差异

在构建实时应用程序时,有时你必须选择如何实现客户端和服务器之间的实时数据交换。WebSockets 和 Socket.IO 可能是现代网络中实现实时通信的两种最流行的解决方案。但我们应该选择哪一个呢?这两种技术有什么区别?让我们来看看吧!


当谈论 WebSocket 时,我们指的是一种通过单个 TCP 连接提供全双工通信通道的 Web 通信协议。简而言之,它允许客户端和服务器之间以最小的开销进行交互,使我们能够构建利用实时通信优势的应用程序。


例如,想象一下,如果你正在构建一个聊天应用程序:你需要尽快接收和发送数据,对吗?嗯,这就是 WebSocket 的正确工作!你可以打开一个 TCP 连接并共享数据,只要你需要,它就保持打开状态。


WebSockets 于 2010 年首次出现在 Google Chrome 4 中,第一个 RFC ( RFC 6455 ) 于一年后(即 2011 年)发布。
WebSocket 的优秀用例包括:

  • 聊天应用程序
  • 多人游戏
  • 协同编辑
  • 社交动态
  • 基于位置的应用程序除此之外还有很多。

Socket.IO

Socket.IO 是一个构建在 WebSocket 之上的 JavaScript 库……以及其他技术。事实上,它在可用时使用 WebSocket,但它已准备好回退到其他技术,例如 Flash Socket、AJAX Long Polling、AJAX Multipart Stream 等等;允许在不支持 WebSocket 的上下文中使用 Socket.IO。

WebSocket 和 Socket.IO 之间的区别

Socket.IO 相对于 WebSocket 的主要优点是:

  • 与 WebSocket 不同,Socket.IO 允许你向所有连接的客户端广播消息。例如,如果你正在编写一个聊天应用程序,并且想要通知所有连接的客户端有新用户加入了聊天,你可以轻松地一次性将该消息广播给每个人。使用普通的 WebSocket,你需要所有已连接客户端的列表,然后直接一一发送消息。
  • 代理和负载均衡器使得 WebSocket 难以实现和扩展。Socket.IO 开箱即用地支持这些技术。
  • 如前所述,当客户端不支持时,Socket.IO 可以回退到 WebSocket 以外的技术。
  • 如果(由于某种原因)WebSocket 连接断开,它不会自动重新连接……但你猜怎么着?Socket.IO 会为你处理这些事情!
  • Socket.IO API 旨在更易于使用。
    这么看来,Socket.IO 有点像“实时通信的天堂”,对吗?嗯,实际上有一些使用普通 WebSocket 的充分理由。

首先,现在每个现代浏览器都支持 WebSocket。Socket.IO 使用更多的样板代码和资源来使其回退到其他技术。大多数时候,你不需要这种级别的支持。即使就网络流量而言,Socket.IO 也要昂贵得多。事实上,使用普通的 WebSockets,浏览器可能只需要运行两个请求:

  • GETHTML 页面的请求
  • UPGRADE与 WebSocket 的连接就是这样。你已准备好开始与服务器进行实时通信!但是 Socket.IO 呢?
  • GETHTML 页面的请求
  • Socket.IO 客户端库 ( 207kb )
  • 三种长轮询 Ajax 请求
  • UPGRADE与 WebSocket 的连接

在我们使用许多 JavaScript 代码和库的世界中,它们的重量正在大幅减轻……207kb 很大了!那么所有这些请求又如何呢?真是浪费网络流量啊!


甚至还有一个npm名为websocket-vs-socket.io(请参阅此处)的包,用于比较这两种技术的网络流量:

WebSocket 网络流量:

讲述WebSocket 和 Socket.IO 两者的差异
WebSocket 网络流量

Socket.IO 网络流量:

讲述WebSocket 和 Socket.IO 两者的差异
Socket.IO 网络流量

两者的差异非常巨大!

编写实时代码

到目前为止,我们只是在纸上看到了一些差异,但是在编写实时应用程序时它们有何不同?


简单的 WebSocket 服务器 在下面的 Node.js 程序中,我们将创建一个在端口 上公开的 WebSocket 服务器3001。每次客户端连接时,我们都会为其会话分配一个唯一的 ID。当客户端发送消息时,我们会按照以下格式进行回复:[<client-id>]: <message>这样他就知道消息已成功发送。

const WebSocket = require("ws");
const UUID      = require("uuid");
const wss       = new WebSocket.Server({ port: 3000 });

wss.on("connection", ws => {
  ws.id = UUID();

  ws.on("message", message => {
    ws.send(`[${ws.id}]: ${message}`);
  });

});

但是,如果我想将该消息广播给每个连接的客户端怎么办?WebSockets 默认不支持消息广播!没错,但是使用普通 WebSocket 仍然可以轻松实现消息广播:

const WebSocket = require("ws");
const UUID      = require("uuid");
const wss       = new WebSocket.Server({ port: 3000 });

function broadcast(clientId, message) {
  wss.clients.forEach(client => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(`[${clientId}]: ${message}`);
    }
  });
}

wss.on("connection", ws => {
  ws.id = UUID();
  ws.on("message", message => broadcast(ws.id, message));
});

正如你所看到的,它WebSocket.Server会跟踪每个连接的客户端,因此我们可以循环它们并将所需的消息发送给每个人!我们刚刚实现了有史以来最简单的聊天服务器!你可以使用任何 WebSocket 客户端测试上面的代码,无论是在客户端还是通过Chrome 扩展。

Socket.IO 承诺会让这一切变得更加容易!我们应该如何使用该库实现相同的服务器?

const io     = require("socket.io");
const server = io.listen(3002);

server.on("connection", socket => {

  socket.on("message", message => {
    socket.emit(`[${socket.id}]: ${message}`);
    socket.broadcast.emit(`[${socket.id}]: ${message}`);
  });

});

正如你所看到的,使用 Socket.IO 本机broadcast方法,我们不会将消息发送回发送者;而是将消息发送回发送者。因此,我们需要手动将该消息发送给客户端。


但有一个问题:你无法在标准 WebSocket 客户端上测试它(正如我们在前面的示例中看到的那样)。这是因为(如前所述),Socket.IO 不使用普通的 WebSocket,而是混合多种技术来支持尽可能多的客户端(并避免某些问题,如上所述)。那么如何测试呢?

<html>
  <head>
  </head>
  <body>
    <script type="text/javascript">
      ioClient = io.connect("http://localhost:3000");
      ioClient.on("connect", socket => {
        ioClient.send("Hello everybody!");
        ioClient.on("message", msg => console.log(msg));
      });
    </script>
  </body>
</html>

你需要使用 Socket.IO 客户端。在上面的示例中,我们使用 CDN 提供的客户端,它允许我们在 Web 浏览器上进行一些快速而肮脏的测试。


正如你所看到的,这两个示例可能看起来并没有那么不同……但是在兼容性方面,你必须记住 Socket.IO 将始终与它自己的客户端库一起使用,因此你将无法使用它用于 Web 开发以外的目的。对于 WebSocket 来说情况并非如此,它可能用于解决大量问题,例如 p2p 通信、实时服务器到服务器数据传输等。

要记住的事情

正如我们在开始时所看到的,Socket.IO 试图解决许多问题。

  • 水平缩放。假设你的聊天应用程序取得了很大成功,并且你需要添加另一台服务器和负载均衡器来处理所有请求。好吧,如果你在“ ”上打开连接server 1,但随后负载均衡器将你切换到“ server 2”,你将收到以下错误:“ Error during WebSocket handshake: Unexpected response code: 400”。Socket.IO 使用 cookie(或根据其原始地址路由连接)解决了该问题,但 WebSockets 没有提供现成的替代机制。
  • 表演。正如我们之前所说,Socket.IO 在普通 WebSockets 传输层上提供了多个抽象层。它还将强制执行 JSON 打包,以将真实的二进制数据从客户端发送到服务器(反之亦然)。如果你需要达到该级别的性能,则需要自定义该库以避免该特定行为。使用普通的 WebSockets,你将永远不会遇到这个问题。那么,我应该选择什么呢?


嗯,这个问题没有一个简单的答案。Socket.IO 肯定会让事情变得更容易一些;你不必担心负载均衡器相关的问题、连接失败和消息广播……但你确定你真的需要这些功能吗?仅 Socket.IO 客户端库就比打包在一起的 React、Redux 和 React-Redux 更重。你确定不能使用浏览器原生的 WebSocket API 吗?


另一件需要记住的事情是,在服务器端实现的 Socket.IO 是一个自定义库/框架,在大多数情况下,由于 Socket.IO 本身应用的抽象,你不会遵循普通的 WebSocket 逻辑。如果你将 Node.js 微服务(比如说)重构为 Go、Elixir、Java 或任何其他语言,则必须重写 Socket.IO 行为背后的大部分逻辑,才能使用普通 WebSocket 实现相同的结果。


例如,考虑向每个连接的客户端广播消息:使用 Socket.IO 只是一种方法(.broadcast)但是在普通的 WebSockets 中,你必须自己实现它,因此你必须重新考虑它的工作方式。因此,也许从一开始就开始使用普通 WebSocket 是值得的,这样用其他语言重构、扩展或实现新功能会更容易(如果你正在编写微服务/lambda 等)。

使用 Apifox 调试 WebSocket 和 Socket.io

Apifox 支持调试 WebSocket 和 Socket.io,通过此调试工具,极大的提高了项目的开发效率,你可点击此处开始尝试。

调试 WebSocket 和 Socket.IO
Apifox