Web套接字和Socket.IO之间的区别



朋友们,美好的一天!

Web套接字和Socket.IO可能是两种最常见的实时通信方式(以下称为实时通信)。但是它们有何不同?

在构建用于实时通信的应用程序时,有时需要选择一种用于在客户端和服务器之间交换数据的工具。Web套接字和Socket.IO是现代Web上最流行的实时通信方式。选择哪一个?这些技术之间有什么区别?让我们找出答案。

网络插座


说到网络套接字,我们指的是网络通信协议,它表示通过简单TCP连接的全双工通信通道。简而言之,这项技术使您能够以最小的成本在客户端和服务器之间建立通信,从而使您能够创建利用实时通信所有优点的应用程序。

例如,假设您正在创建聊天:您需要尽快接收和发送数据,对吗?Web套接字就可以了!您可以打开一个TCP连接,并在需要时保持打开状态。

Web套接字于2010年出现在Google Chrome 4中,第一个RFC(6455)于2011年发布。

在以下情况下使用Web套接字:

  • 聊天室
  • 多人游戏
  • 协同编辑
  • 社会(新闻)提要
  • 基于位置的应用

等等

套接字


Socket.IO是一个基于Web套接字...和其他技术的JavaScript库(写在顶部)。如果可用,则使用Web套接字;如果不可用,则使用Flash Socket,AJAX Long Polling,AJAX Multipart Stream等技术。一个简单的类比是Fetch API和Axios的比较。

Web套接字和Socket.IO之间的区别


Socket.IO的主要优点如下:

  • -, Socket.IO . , . . -, .
  • - . Socket.IO .
  • , Socket.IO () .
  • Socket.IO .
  • Socket.IO .

似乎Socket.IO是实时通信的最佳工具。但是,在某些情况下,最好使用Web套接字。

首先,所有现代浏览器都支持Web套接字。因此,您很少需要Socket.IO提供的其他技术的支持。

如果我们谈论网络流量,则Web套接字仅发送两个请求:

  • 获取以获取HTML页面
  • 升级用于连接Web套接字

这使您可以连接到服务器。Socket.IO呢?

  • 获取以获取HTML页面
  • Socket.IO客户端库(207kb
  • 三个长轮询Ajax请求
  • 升级用于连接Web套接字

在JS的世界中,207kb非常多。多么不合理地使用网络流量!

在npm中,有一个软件包“ websocket-vs-socket.io”,可让您比较以下技术的网络流量:

Web套接字网络流量:




Socket.IO网络流量:




区别很明显!

编写代码


简单的Web套接字服务器


在Node.js上的程序中,我们将创建一个在端口3001上运行的服务器。每次客户端连接时,我们都会为其分配一个唯一的ID。向客户发送消息时,我们将通知他成功:[<client-id>]:<message>

const WebSocket = require('ws')
const UUID = require('uuid')
const wss = new WebSocket.Server({ port: 3001 })

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

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

精细!但是,如果我们想向每个连接的客户端发送消息怎么办?Web套接字默认情况下不支持邮件。可以如下实现:

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

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

wss.on('conection', ws => {
  ws.id = UUID()
  ws.on('message', message => broadcast(ws.id, message))
})

简单轻松!如您所见,WebSocket.Server会保留每个连接的客户端的记录,因此我们可以迭代并向每个人发送消息。您可以在计算机(MacOS)浏览器(Chrome)中测试代码

Socket.IO上的简单服务器


这并不困难。Socket.IO可以使它更容易吗?我们如何在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}`)
  })
})

代码几乎短了一半!如您所见,广播方法不会将通知发送给发件人,因此我们被迫手动执行此操作。

有一个问题:无法在常规的Web套接字客户端上测试代码。如前所述,这是由于Socket.IO不使用纯Web套接字,而是使用许多技术来支持所有可能的客户端的事实。那么我们如何测试其性能呢?

// head
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2.3.0/dist/socket.io.slim.js"></script>

// body
<script>
  ioClient = io.connect('http://localhost:3002')
  ioClient.on('connect', socket => {
    ioClient.send('hello world')
    ioClient.on('message', msg => console.log(msg))
  })
</script>

您必须使用特殊的客户端。在上面的示例中,我们从CDN加载它。该客户端允许我们在浏览器中进行快速(脏)测试。

如您所见,我们的示例并没有太大不同。但是,如果我们谈论兼容性,则应记住Socket.IO使用其自己的库,不能将其用于与Web开发无关的目的。同时,Web套接字可用于解决各种任务,例如P2P通信,服务器之间的实时数据交换等。

在笔记上


水平缩放。假设您的聊天越来越流行,您需要添加其他服务器和负载平衡器来处理请求。好吧,如果您打开到“服务器1”的连接,那么平衡器会将您切换到“服务器2”,您将收到错误:“ WebSocket握手期间错误:意外的响应代码:400”。 Socket.IO通过使用cookie(或通过基于源地址的路由连接)解决了此问题,并且Web套接字没有这种机制。
性能。如前所述,Socket.IO在Web套接字的传输层之上提供了几个抽象层。另外,此处使用将数据打包为JSON格式,因此不可能将二进制数据发送到服务器(反之亦然)。如果需要这种功能,则必须“构想”库代码以确保所需的行为。使用Web套接字不会出现此类问题。

那么该选择什么呢?


你决定。

Socket.IO使生活更轻松,您无需担心与负载平衡,断开连接或发送消息有关的问题……但是您是否需要这种功能?Socket.IO客户端库的重量超过React,Redux和React-Redux软件包的总和。确定要限制自己使用网络套接字吗?

要记住的另一件事是,在服务器端使用Socket.IO时,大多数代码将以该库提供的抽象形式编写。如果您需要用Go,Elixir,Java或其他编程语言重写Node.js微服务,则必须重写几乎所有逻辑。例如,要将消息发送到Socket.IO,则使用“广播”方法(在Web套接字上手动实现),因此在重构时,您将必须了解该方法的工作方式。在这种情况下,应该首选Web套接字,因为它们更容易适应。

感谢您的关注。

All Articles