WebSockets带来乐趣和利润

发布于:2021-01-06 17:01:00

0

68

0

WebSockets 通信协议 网络

在现代网络上,无缝通信是必须的。随着互联网速度的提高,我们希望实时获得数据。为了满足这一需求,WebSocket是一种流行的通信协议,于2011年完成,该协议使网站能够立即发送和接收数据。借助WebSocket,您可以构建可在开放网络上运行的多人游戏,聊天应用程序和协作软件。 

在开始怀疑到底发生了什么之前,我用WebSockets构建了多个项目。这个问题使我无所适从,很高兴与您分享我所学到的知识。在本文中,我们将:

  1. 探索WebSockets解决的问题并查看替代方法

  2. 深入了解WebSockets的工作原理

  3. 查看基于WebSocket的应用程序的一些简单代码

  4. 通过一些实际的实现进行讨论

在本文的最后,您应该轻松讨论WebSockets的工作原理,甚至可能会启发您在下一个项目中使用它。

互联网上的消息传递

让我们从基础开始:WebSocket是一种允许客户端与服务器建立双向(“全双工”)通信的技术。(快速回顾:客户端是用户计算机上的应用程序,服务器是存储网站和相关数据的远程计算机)。

该定义中的关键字是双向的:使用WebSocket,客户端和服务器都可以触发彼此的通信,并且两者都可以同时发送消息。为什么这很重要?为了完全理解WebSocket的功能,让我们退后一步,看看计算机可以从服务器获取数据的几种常见方式。

请求-响应

在当今大多数网站都使用的传统HTTP系统中,Web服务器被设计为通过HTTP消息接收并响应来自客户端的请求。这种传统的通信只能在一个方向上启动:从客户端到服务器。服务器代码定义服务器应期望的请求类型以及如何响应每个请求。这种交流的常见隐喻是餐厅厨房。它是这样的:

  1. 您(客户端)下达了服务员带到厨房(服务器)的订单(HTTP请求)。 

  2. 厨房收到订单并检查他们是否知道如何进行(服务器处理该请求)。

  3. 如果厨房知道如何做菜,他们会准备订单(服务器从数据库中获取数据或从服务器中获取资产)。

  4. 如果厨房无法识别该命令或不允许该服务,则他们将坏消息发送回服务员(如果服务器不知道如何或不允许响应该请求,则将其发回)错误代码,例如404)。

  5. 无论哪种方式,服务员都会返回给您(您将获得带有相关代码的HTTP响应,例如200 OK或403 Forbidden)。

这里要注意的重要一点是,厨房不知道订单来自谁。这种技术上的说法是“ HTTP是无状态的”:它将每个新请求视为完全独立的。我们确实有解决办法,例如,客户端可以发送cookie来帮助服务器识别客户端,但是HTTP消息本身是不同的,可以独立读取和实现。

这里的问题是:厨房不能派服务员给你。当您将服务员送去时,它只会给服务员一道菜或坏消息。厨房没有您的概念,只有您的订单。在服务器方面,客户端从服务器获取更新信息的唯一方法是发送请求。

想象一下您正在与朋友聊天的聊天应用程序。您将一条消息作为请求发送到服务器,并带有一些文本作为有效负载。服务器收到您的请求并存储消息。但是,它无法联系到您朋友的计算机。您朋友的计算机还需要发送请求以检查新消息;只有这样服务器才能发送您的消息。

就目前而言,您和您的朋友(都是客户端)都需要不断检查服务器的更新,从而在每条消息之间造成尴尬的延迟。太傻了吧?发送消息时,您希望服务器立即对您的朋友执行ping操作,说“嘿,您收到消息了!这里是!” 当您需要加载静态页面时,HTTP请求响应就可以很好地工作,但是当您的通信对时间敏感时,HTTP请求响应就不够了。

短轮询

一种解决此问题的简单方法是称为短轮询的技术。只需让客户端每隔500毫秒(或经过一定的固定延迟)重复ping服务器。这样,您每500ms就会获得新数据。这有一些明显的缺点:存在500毫秒的延迟,它消耗大量请求的服务器资源,如果数据不经常更新,大多数请求将返回空。

长时间轮询

延迟接收数据的另一种解决方法是一种称为长轮询的技术。在这种方法中,服务器接收到一个请求,但是直到它从另一个请求获取新数据后才响应。长轮询比重复ping服务器更有效,因为它节省了解析请求标头,查询新数据以及发送经常为空的响应的麻烦。但是,服务器现在必须跟踪多个请求及其顺序。同样,请求可能会超时,并且需要定期发出新请求。

服务器发送的事件(SSE)/ EventSource

另一种发送消息的技术是服务器发送事件API,它允许服务器通过利用JavaScript EventSource接口将更新推送到客户端。EventSource使用特殊的文本/事件流标头通过HTTP与服务器建立持久的单向连接,并侦听消息,这些消息在您的代码中被视为JavaScript事件。 

这几乎是我们所需要的—现在我们可以从服务器接收更新!由于服务器发送事件(SSE)是单向的,因此非常适合您不需要向服务器发送任何数据的应用程序,例如Twitter风格的新闻提要或股票行情的实时仪表板。另一个优点是服务器发送事件可以通过HTTP进行工作,并且该API相对易于使用。但是,旧版浏览器不支持SSE ,并且大多数浏览器都会限制您可以同时建立的SSE连接数。但是,对于我们的聊天应用程序来说,这还不够:接收实时更新很棒,但是我们也希望能够发送这些更新。

Web套接字

因此,我们需要一种方法来将信息发送到服务器,并在更新进入时从服务器接收更新。这使我们回到了前面提到的双向(“全双工”)通信。输入WebSocket!几乎所有现代浏览器都支持WebSocket API,它使我们能够与服务器完全打开这种双向连接。而且,服务器可以跟踪每个客户端并将消息推送到客户端的子集。大!借助此功能,我们可以邀请我们所有的朋友加入我们的聊天应用程序,并向其中的所有人,其中的一些人或您最好的朋友发送消息。

WebSockets在幕后

那么,这种魔术到底是如何工作的呢?不要被设置吓倒了-像socket.io这样的现代WebSocket库抽象了很多设置,但是了解该技术的工作原理仍然很有帮助。如果在本节末尾您对更多细节感兴趣,请查看令人惊讶的可读性WebSocket RFC。

在上一节中,我们多次提到了HTTP。HTTP是一种协议,是计算机如何在网络上通信的一组规则。它由请求和响应组成,每个请求和响应都包含一个请求行(“ GET /assets/icon.png”),标头和一个可选的消息主体(例如,用于POST请求中,用于将一些数据发送到服务器)。

WebSocket是用于发送和接收消息的另一种协议。HTTP和WebSocket都通过TCP(传输控制协议)连接发送消息,TCP连接是一种传输层标准,可确保以包的形式发送的字节流可靠且可预测地从一台计算机传递到另一台计算机。因此,HTTP和WebSocket在数据包/字节级别使用相同的传递机制,但是用于构造消息的协议是不同的。

为了与服务器建立WebSocket连接,客户端首先发送带有升级标头的HTTP “握手”请求,指定客户端希望建立WebSocket连接。该请求被发送到ws:或wss :: URI(类似于http或https)。如果服务器能够建立WebSocket连接并且允许该连接(例如,如果请求来自经过身份验证或列入白名单的客户端),则服务器将发送成功的握手响应,由HTTP代码101 Switching Protocols表示。

连接升级后,协议将从HTTP切换到WebSocket,而数据包仍通过TCP发送时,通信现在符合WebSocket消息格式。由于TCP是传输数据包的基础协议,是全双工协议,因此客户端和服务器都可以同时发送消息。邮件可能是零散的,因此可以发送大型邮件而无需事先声明大小。在这种情况下,WebSockets将其分解为多个帧。每个帧都包含一个小标题,用于指示有效载荷的长度和类型以及这是否是最后一帧。

服务器可以打开与多个客户端的WebSocket连接,甚至可以与同一客户端的多个连接。然后,它可以向一个,一些或所有这些客户端发送消息。实际上,这意味着多个人可以连接到我们的聊天应用程序,并且我们可以一次向其中的一些人发送消息。

最后,当准备关闭连接时,客户端或服务器都可以通过“关闭”消息发送。

哇!接下来的工作真不错!让我们休息一下,然后看一些示例代码。

一个简短的例子

既然您已经不再需要拉伸了(我之前不是在开玩笑!),那么让我们从技术概述切换到查看一些代码。这将不那么复杂了-正如我之前提到的,现代工具使我们不必担心握手或构图OpCode。

在前端,我们将使用JavaScript建立与启用WebSockets的服务器的连接,然后将消息作为JavaScript事件进行侦听-就像侦听用户生成的事件(如单击和按键)一样。在普通JavaScript中,我们通过创建一个新的WebSocket对象并为open,message和close事件添加事件侦听器来做到这一点。我们还使用send方法将数据发送到服务器。

const socket = new WebSocket('ws://localhost:8080'); socket.addEventListener('open', function (event) {    socket.send('Hello Server!');  });  socket.addEventListener('message', function (event) {    console.log('Message from server ', event.data); }); socket.addEventListener('close', function (event) {    console.log('The connection has been closed');  });

在服务器上,我们同样需要侦听WebSocket请求。例如,在Node.js中,我们可以使用流行的ws包打开连接并侦听消息:

const WebSocket = require('ws'); const ws = new WebSocket.Server({ port: 8080 }); ws.on('connection', function connection(wsConnection) {   wsConnection.on('message', function incoming(message) {        console.log(`server received: ${message}`);   });   wsConnection.send('got your message!'); });

尽管在此示例中,我们正在发送字符串,但是WebSockets的一个常见用例是发送字符串化的JSON数据甚至二进制数据,从而使您能够以方便使用的格式来构造消息。

对于更完整的示例,Socket.io是用于建立和管理WebSocket连接的流行前端框架,它具有构建Node / JavaScript聊天应用程序的出色演练。该库自动在WebSockets和长时间轮询之间切换,并且还简化了向连接的用户组广播消息的过程。

在野外

尽管您可以手动编写WebSocket服务器代码,但WebSockets已方便地内置在流行的框架中。我们已经触及了前端的Socket.io库。在较大的项目中,WebSocket的其他一些实现是:

  • Ruby on Rails中的ActionCable,一个完整的Ruby框架 

  • Django中的通道,全栈Python框架 

  • 大猩猩Go语言

  • Meteor,基于WebSockets而不是HTTP的全栈JavaScript框架

  • GraphQL服务器Apollo,可帮助使用WebSockets实时获取数据

那么,哪些类型的项目可以从WebSockets中受益呢?任何需要实时双向通信的项目都是一个很好的用例。以下是通常由WebSocket支持的几种应用程序:

  1. 聊天应用程序:概念上简单的WebSockets实现;用户将消息发送到服务器,服务器立即将这些消息推送给收件人。不要拖延!服务器还可以在通道中存储多组连接,从而允许您一次向多个人发送消息,或者在一个房间中查看来自多个人的消息,例如Slack通道。

  2. 多人游戏:多人游戏的一种常见模式是让服务器存储游戏状态作为真相来源。玩家将执行发送到服务器的动作或动作,这将更新游戏状态并将其推出给所有玩家。使用HTTP,每个玩家都需要定期请求游戏状态。使用WebSockets,每个动作都会立即传递给所有玩家。

  3. 协作应用程序:需要在共享文档或画布上工作吗?您可以按照上面的模式,允许多个用户绘制或键入文档,并为所有连接的人立即更新。

  4. 开发人员工具: CircleCI等持续集成工具使用WebSockets在构建完成后立即通知您。是否需要发送有关网站性能和访问者数量的客户指标?打开WebSocket连接,并在服务器收到更新后立即发送更新。

  5. 位置相关的应用程序:当用户的GPS坐标已更改时,更新服务器,然后根据其当前坐标向用户发送新数据。

实时回顾

希望到目前为止,您已经在WebSockets上出售了!我们有很多基础知识:我们追踪了WebSockets解决的问题和替代解决方案,探讨了WebSockets如何在后台运行,甚至研究了一些示例代码和常见用例。 

WebSocket协议是构建实时通信应用程序的绝佳工具,但与所有工具一样,它不是灵丹妙药。WebSocket连接本来是持久的,所以对于简单的应用程序来说可能会过大。对于单向新闻提要,指标提要或您需要更新客户端但又不会收到信息的任何应用程序,“服务器发送事件”或普通的旧HTTP调用设置起来更快捷,更简单。但是,对于多人游戏和协作应用程序,WebSockets开辟了无限的可能性。实时网络正在发展,WebSocket协议是其发展的关键要素。继续使用并永久使用它!