计算机网络 --- WebSocket协议 和 Signalr

embedded/2024/12/22 20:06:32/

计算机网络 --- WebSocket协议 和 Signalr

  • 什么是WebSocket
  • 什么是Signalr
    • Signalr Example -- SimpleChat

什么是WebSocket

  • HTTP是基于TCP协议的,同一时间里,客户端和服务器只能有一方主动发数据,是半双工通信。
  • 通常,打开某个网页,我们每点击一次网页上的某个选项,前端就会发送一次HTTP请求,网站返回一次HTTP响应。这种由客户端主动请求,服务器响应的方式满足大部分网页的功能场景。但这种情况下,服务器不会主动给客户端发消息。而类似网页游戏这样的场景,是需要客户端和服务器之间互相主动发大量数据的。
  • 因此,我们需要一个基于TCP的新协议,即新的应用层协议WebSocket。
  • 它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种

在这里插入图片描述

  • 其他特点包括:
  • 建立在 TCP 协议之上,服务器端的实现比较容易。
  • 与 HTTP 协议有着良好的兼容性。默认端口也是80和
  • 并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
  • 数据格式比较轻量,性能开销小,通信高效。
  • 可以发送文本,也可以发送二进制数据。
  • 没有同源限制,客户端可以与任意服务器通信。
  • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
    在这里插入图片描述
  • 使用WebSocket注意事项
  • 资源消耗:WebSocket 连接是持久的,这意味着服务器端需要分配和管理每个连接的资源。如果同时有大量连接存在,可能会对服务器的性能和资源消耗造成压力
  • 安全性考虑:由于 WebSocket 允许服务器端向客户端发送实时数据,因此存在安全风险。如果不正确地实施安全措施,可能会导致跨站点脚本攻击(XSS)和其他安全漏洞
  • 连接状态维护:与传统的 HTTP 请求不同,WebSocket 建立了一个持久的连接,需要维护连接状态。这意味着服务器端需要消耗额外的资源来管理连接、保持连接状态和处理连接断开等情况
  • 防火墙和代理限制:某些网络环境中的防火墙或代理服务器可能会阻止 WebSocket 连接。这可能导致在特定网络配置下,无法建立或保持 WebSocket 连接,从而影响实时通信功能的可用性

什么是Signalr

  • 因为WebSocket是无状态的,如果因为网络问题中断的话, 则重连之后, 服务器会丢失所有客户端的信息. 所以使用原生WebSocket的话, 需要自己在服务器端实现状态管理.
  • SignalR 是一个开源的 Microsoft .NET 库,用于实现实时双向通信功能。它简化了在 Web 应用程序中实现实时功能的开发过程,允许服务器端代码能够主动推送数据到客户端,并支持客户端与服务器之间的实时双向通信。
  • SignalR 支持多种传输协议
  • WebSocket
  • Server-Sent Events(SSE)
  • 长轮询
  • Forever Frame
  • Signalr对于每个链接提供了一个connectionId, 这样可以服务器端可以通过connectionId识别出来客户端, 实现状态管理

SignalR 的主要特点包括:

  • 实时双向通信:SignalR 允许服务器端向客户端实时推送数据,同时也支持客户端向服务器端发送消息,实现双向通信。
  • 广播和组管理:SignalR 提供了广播功能,可以将消息同时发送给多个客户端。它还支持将客户端分组,可以根据需要将消息发送给特定的客户端组。
  • 自动重连和状态管理:SignalR 具有自动重连功能,如果连接中断,它会尝试重新建立连接。同时,它还能够管理客户端和服务器之间的连接状态,包括连接建立、连接断开和错误处理等。
  • 扩展性和可定制性:SignalR 可以在不同的扩展点进行定制,开发人员可以根据需要修改消息传输、身份验证和授权等方面的行为。
  • 总体而言,SignalR 提供了一种简单且强大的方式来实现实时双向通信功能,并且能够与 ASP.NET、ASP.NET Core 和其他 .NET 平台无缝集成。

Signalr Example – SimpleChat

服务器端

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;namespace SignalRServer
{public class Startup{public void ConfigureServices(IServiceCollection services){services.AddSignalR();}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();
//将Hub和Http uri进行绑定app.UseEndpoints(endpoints =>{endpoints.MapHub<ChatHub>("/chathub");});}}public class ChatHub : Microsoft.AspNetCore.SignalR.Hub{public async Task Broadcast(string message){//"ReceiveMessage" 是客户端注册的接收消息的回调函数的名字await Clients.All.SendAsync("ReceiveMessage", message);}public async Task SendMessage(string message){var connectionId = Context.ConnectionId;await Clients.All.SendAsync("ReceiveMessage", connectionId, message);}}
}
  • 在上述代码中,我们首先在 ConfigureServices 方法中添加了 SignalR 服务。然后,在 Configure 方法中注册了 ChatHub,并将其映射到 /chathub 路由。
  • ChatHub 是一个继承自 Microsoft.AspNetCore.SignalR.Hub 的类,它包含了一个名为 SendMessage 的方法,用于接收客户端发送的消息,并将消息通过 Clients.All.SendAsync 发送给所有连接的客户端。

客户端

from signalrcore.hub_connection_builder import HubConnectionBuilder# 创建 SignalR 连接
connection = HubConnectionBuilder() \.with_url("http://example.com/chathub") \.build()# 定义收到消息时的回调函数
def on_message(message):print("Received message:", message)# 注册消息回调函数
connection.on("ReceiveMessage", on_message)# 启动连接
connection.start()# 发送消息, SendMessage 是服务器端Hub里定义的接受消息的方法名
while True:message = input("Enter a message to send: ")connection.send("SendMessage", message)# 断开连接
connection.stop()
  • 在这个例子中,我们使用 signalrcore 库创建了一个 SignalR 连接,并指定了服务器的 URL(http://example.com/chathub)。然后,我们定义了一个回调函数 on_message,用于处理接收到的消息。接下来,我们通过调用 connection.on() 注册回调函数,以便在收到消息时触发回调函数。
  • 然后,我们通过调用 connection.start() 启动连接。在连接启动后,我们进入一个循环,等待用户输入要发送的消息,并通过调用 connection.send() 发送消息到服务器.

注意

  • Hub 类是Transient的, 也就是用完一次就会被销毁
  • 不要将状态存储在 Hub 类的属性中。每次调用 Hub 方法时,都会在一个新的 Hub 实例上执行。
  • 不要直接通过依赖注入实例化一个 Hub。可以使用 IHubContext 来从应用程序的其他位置向客户端发送消息。
  • 在调用依赖于 Hub 保持活动状态的异步方法时,请使用 await。例如,如果在没有使用 await 的情况下调用类似 Clients.All.SendAsync(…) 的方法,并且在 SendAsync 完成之前 Hub 方法已经完成,那么该方法可能会失败.

使用 IHubContext 从应用程序的其他位置向客户端发送消息

public class NotificationService
{private readonly IHubContext<ChatHub> _hubContext;public NotificationService(IHubContext<ChatHub> hubContext){_hubContext = hubContext;}public async Task SendNotificationToAllClients(string message){await _hubContext.Clients.All.SendAsync("ReceiveNotification", message);}
}

http://www.ppmy.cn/embedded/17035.html

相关文章

如何利用交易形态的失败进行现货黄金?

进行现货黄金理财&#xff0c;除了需要投资者对黄金投资有热情之外&#xff0c;有方法也是很重要的&#xff0c;光有热情而没有技术&#xff0c;我们的资金很可能会成为其他人的囊中之物。但如果有了现货黄金理财的技术&#xff0c;情况就可能扭转过来。下面我们就从买入的角度…

js音频指定扬声器

做音视频开发时候&#xff0c;看到阿里音视频能力&#xff0c;有这个功能&#xff0c;怀着好奇的心去搜索果然发现是有办法做到的&#xff0c;可能比较冷门平时用不到&#xff0c;记录下&#xff1b; const devices await navigator.mediaDevices.enumerateDevices(); const a…

【银角大王——Django课程——创建项目+部门表的基本操作】

Django框架员工管理系统——创建项目部门表管理 员工管理系统创建项目命令行的形式创建Django项目——创建app注册app——在sttings中的INSTALLED_APPS [ ]数组中注册 设计表结构&#xff08;django&#xff09;连接数据库——在settings里面改写DATABASESDjango命令执行生成数…

在react配置使用less的最优解

在react配置使用less的最优解 react默认支持用scss&#xff0c;不支持less&#xff0c;直接使用less时会报错&#xff0c;因此当使用less的时候需要进行额外配置。至于技术选型选择less或scss完全取决于你的个人偏好。你当然可以采取别的方式去实现对less的配置。但是我这里只…

Redis入门到通关之数据结构解析-动态字符串SDS

文章目录 Redis数据结构-动态字符串动态扩容举例二进制安全SDS优点与C语言中的字符串的区别 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间…

Java 基础:设计模式之工厂方法模式

工厂方法模式&#xff08;Factory Method Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一个创建对象的通用接口&#xff0c;但将实际创建逻辑推迟到子类中实现。这种模式允许客户端使用抽象接口来创建特定类型的对象&#xff0c;而无需了解具体的实现细节。以…

模板方法模式:定义算法骨架,子类实现具体步骤

在软件开发中&#xff0c;经常会遇到一些算法或过程&#xff0c;它们的总体步骤是固定的&#xff0c;但在某些步骤上可能会有不同的实现。模板方法模式是一种行为型设计模式&#xff0c;它在超类中定义了一个算法的骨架&#xff0c;将一些步骤延迟到子类中实现。这种模式允许子…

LeetCode in Python 48. Rotate Image/Matrix (旋转图像/矩阵)

旋转图像/矩阵的重点是寻找旋转前后对应位置的坐标关系。 示例&#xff1a; 图1 旋转图像/矩阵的输入输出示意图 代码&#xff1a; class Solution:def rotate(self, matrix):n len(matrix)for i in range(n // 2):for j in range(i, n - 1 - i):topleft matrix[i][j]ma…