使用 SignalR 库实现实时文本对话的示例
作者:丹尼斯·巴兰特、埃内吉·胡多布雷兹尼克
HTTP(超文本传输协议)协议仍然主要用于通过互联网传输数据。其更现代、更安全的加密衍生品HTTPS(HTTP Secure)。它们基于客户端-服务器架构,其中客户端(英语客户端)向服务器(英语服务器)发送请求(英语 HTTP 请求),服务器用响应(英语 HTTP 响应)对其进行响应。
HTTP 和 HTTPS 协议适用于简单的请求-响应传输(例如,根据客户端的请求传输 HTML 文件)。使用这两种协议,用户只有在发送新请求时才能获取更新的数据,因此它们并不是最适合实时数据传输(例如在线聊天、在线视频游戏、位置跟踪...)。现代 Web 应用程序的许多功能都是基于的。敏捷性可以通过许多不同的更好的方式来实现,每种方式都有自己的优点和缺点。
最简单的实现方法是定期轮询,即客户端在每个轮询间隔内向服务器重复发送新数据请求,而不管内容是否发生变化。尽管这种方法很简单,但它并不适合需要许多客户端访问服务器的大型服务,因为大量不必要的重复请求可能会使服务器过载,从而降低服务的性能。
这种改进是通过引入长期轮询来实现的,其中客户端以相同的方式向服务器发送请求,但服务器在检测到新数据存在之前不会响应它们。这种方法的缺点是客户端必须定义一定的时间间隔,在此之后客户端会将服务器的不活动视为错误。这给客户端和服务器设置增加了一层额外的复杂性。
现代 HTML5 标准还提供了一个称为服务器发送事件的 API。在这种协议中,客户端不必定期向服务器发送请求,但服务器会在发生更改时重新发送必要的数据,从而促进实时通信。
HTML5 标准还提供了 WebSockets 协议,可实现真正的双向实时通信。在建立开始时,会执行握手,客户端和服务器就他们将使用的标准集达成一致。成功握手后,两个参与者之间会建立一个有小延迟的永久连接。当涉及点对点连接(客户端和服务器之间的直接连接)时,该协议特别有用。
除了经典的客户端-服务器架构之外,还有其他解决方案,其中客户端之间的连接不通过服务器,而是直接在同时扮演客户端和服务器角色的客户端之间(这些对等网络)。 WebRTC 是此类网络中实时通信的流行协议。
在.NET环境中进行实时通信,我们可以使用开源的SignalR库,它是ASP.NET Core Web框架的一部分,因此很容易将其添加到现有项目中作为附加级别的中间件。处理传入的请求。该库模拟从服务器端对客户端的方法调用和从客户端对服务器的方法调用(远程过程调用 - RPC),但不保证编号的适当性。参数及其类型。从服务器上,我们可以调用所有客户端、一组特定客户端或仅一个客户端上的方法。
它的主要优点是实现简单,这要归功于许多不同平台的软件开发包 (SDK),这向程序员隐藏了服务的内部工作原理,并且可以通过 Azure SignalR 服务轻松托管。另一个优点是服务本身会在客户端和服务器之间选择最合适的连接类型(如上所述)。
该库的使用基于称为集线器的特殊类,它代表客户端和服务器之间连接的抽象。对于它们,我们定义客户端可以在服务器上调用的方法。
下面的示例显示了简单文本对话实现的示例。首先,我们定义服务器上对话的基本节点。该类的方法表示可以由服务器上的客户端调用的方法。当调用SendMessage方法时,客户端发送用户ID(userId)和消息内容(message),而服务器则在所有客户端上调用带有指定参数的ReceiveMessage方法。
下面的示例显示了使用官方库 (@microsoft/signalr) 的 JavaScript Web 客户端实现。客户端连接到节点 URL(以下示例中的 /chat)。连接由连接对象表示。 on 方法表示方法调用的侦听器,其名称作为第一个参数给出,第二个参数给出对事件执行的函数。我们通过连接对象的invoke方法来实现服务器上的方法,该方法需要方法的名称作为第一个参数,后面跟着它的参数。
默认情况下,数据以 JSON 格式在服务器和客户端之间传输,但该库还支持更高效的 MessagePack 格式。
尽管该库极大地方便了开发,但它也有其缺点。主要问题之一是系统自托管和确保不间断运行的可扩展性,因为其实施很难分布在多个单独的服务器上。如果我们想要减少远程用户的延迟并在多个不同位置进行托管,那么这一点尤其困难,因为解决方案设计仅限于一个。此外,该库不确保消息的可靠传递和排序,这可能会降低用户体验。