SignalR服务器端消息推送

目录

一、什么是SignalR

二、SignalR基本使用

三、单台服务器协商协议

四、多台服务器协商协议

五、SignalR分布式部署

六、SignalR身份认证

七、部分客户端的消息推送(私聊功能)


一、什么是SignalR

       我们知道,在传统的 HTTP 中,只能客户端主动向服务器端发起请求,服务器端无法主动向客户端发送消息。有的业务场景下,我们需要服务器端主动向客户端发送消息,比如OA系统就需要服务器端主动向客户端发送请假申请审批结果,站内消息系统就需要服务器端主动通知客户端“有新消息”。我们可以用长轮询来实现这样的功能,也就是浏览器端先向服务器端发送 AJAX 请求,但是服务器端不立即给浏览器端发送响应,而是一直挂起这个请求,直到服务器端有需要推送给客户端的消息,服务器端才把要推送的消息作为响应发送给浏览器端。由于HTTP 并不是为这种长轮询机制设计的,因此长轮询对服务器的资源消耗非常大:而且由于 HTTP 是文本传输协议,因此数据传输效率低。

      为了实现服务器端向客户端推送消息,在 2008 年诞生了 WebSocket 协议,并且该协议在2011 年成为国际标准。目前所有的主流浏览器都已经支持 WebSocket 协议。WebSocket 基TCP(transmission control protocol,传输控制协议),支持二进制通信,因此通信效率非常高,它可以让服务器处理大量的并发 WebSocket 连接:WebSocket 是双工通信,因此服务器可以高效地向客户端推送消息。
ASP.NET Core SignalR是NET Core 平台中对 WebSocket 的封装,从而让开发人员可以更简单地进行 WebSocket 开发。

二、SignalR基本使用

        虽然 WebSocket 是独立于HTTP 的,但是我们一般仍然把 WebSocket 服务器端部署到 Web服务器上,因为我们需要借助 HTTP 完成初始的握手,并且共享HTTP 服务器的端口,这样就可以避免为 WebSocket 单独打开新的服务器端口。因此,SignalR 的服务器端一般运行在ASP.NET Core 项目中。

       SignalR 中一个重要的组件是集线器 (hub),它用于在 WebSocket 服务器端和所有客户端之间进行数据交换,所有连接到同一个集线器上的程序都可以互相通信。我们既可以通过集线器来完成服务器端向客户端的消息推送,也可以完成客户端之间的消息推送,当然 WebSocket 也允许客户端向服务器端发送消息。

比如我们的举个例子,就是我们经常用的聊天框功能

第一步:我们可以创建一个ASP.NET Core Web API 项目,并且在项目中创建一个继承自 Hub 类(位于 Microsoft.Asp.NetCore.SignalR 命名空间下)的 ChatRoomHub 类,所有的客户端和服务器端都通过这个集线器进行通信。

public class ChatRoomHub:Hub2 
{
   public Task SendPublicMessage(string message)
   {
      string connId = this.Context.ConnectionId;
      string msg =$"{connId}{DateTime.Now}:{message}";
      return Clients.All.SendAsync("ReceivePublicMessage", msg);
   }
}

第二步:编辑 Programcs,在 builder,Build 之前调用 builder.Services.AddSignalR 注册所有SignalR 的服务,在 app.MapControllers 之前调用 app.MapHub<ChatRoomHub>("/Hubs)ChatRoomHub")启用 SignalR 中间件,并且设置当客户端通过 SignalR 请求“/HubsChatRoomHub”这个路径的时候,由 ChatRoomHub 进行处理。

builder.Services.AddsignalR();
string[] urls = new[] { "http://localhost:3000"} ;
builder.Services.AddCors(options =>
    options.AddDefaultPolicy(builder => builder.withOrigins(urls)
   .AllowAnyMethod().AllowAnyHeader().AllowCredentials())
);
var app = builder.Build();
app.UseCors();
app.UseHttpsRedirection(); app.UseAuthorization();
app.MapHub<ChatRoomHub>("/Hubs/ChatRoomHub"); 
app.MapControllers();

第三步:我们需要编写一个静态 HTML 页面提供交互界面。按照前后端分离的理念,我们应该把 HTML页面放到一个单独的前端项目中。我们对用户在输入框内的按键进行监听,当用户按 Enter 键的时候,我们就调用集线器中的 SendPublicMessage 方法把用户输入的消息发送给服务器端服务器端再把消息转发给连接到这个集线器的全部客户端。这样我们就实现了一个简单的聊天室。

三、单台服务器协商协议

       SignalR其实并不只是对WebSocket的封装,它支持多种服务器推送的实现方式,包括WebSocket、服务器发送事件和长轮询。SignalR 的JavaScript 客户端会先尝试用 WebSocket 连接服务器;如果失败了,它再用服务器发送事件方式连接服务器; 如果又失败了,它再用长轮询方式连接服务器。因此 SignalR 会自适应复杂的客户端、网络、服务器环境来支持服务器端推送的实现。

        SignalR 的JavaScript 客户端和服务器之间会首先进行一次“协商”,确定采用什么协议进行通信,这个协商过程我们有时候也称之为“握手”。协商完成后,客户端和服务器之间再建立 WebSocket 通信。在协商的时候,服务器端就会为这个客户端后面的连接创建一些上下文信息,在建立 WebSocket 连接的时候就会使用服务器端创建的那些上下文信息,也就是说服务器端会在协商请求和 WebSocket 请求之间保持状态。

四、多台服务器协商协议

       在多台服务器组成的集群中,这样处理就会带来问题。比如,协商请求被服务器 A 处理,而接下来的 WebSocket 请求却被服务器 B 处理,由于服务器A 中没有这个客户端在协商阶段的上下文信息,因此 WebSocket 请求处理失败了。
      解决 SignalR 在多台服务器组成的集群中的这个问题,有两个方法:黏性会话和禁用协商
黏性会话指的是,我们对负载均衡服务器进行配置,以便把来自同一个客户端的请求都转发给同一台服务器。这样就避免了协商请求和 WebSocket 请求由不同服务器处理的问题。禁用协商的解决策略很简单,就是 SignalR 客户端不和服务器端进行网络协议的协商,而有接向服务器发出 WebSocket 请求。由于没有协商过程,因此也就没有两次请求状态保持的向藏,而且 WebSocket 连接一旦建立后,在客户端和服务器端直接就建立了持续的网络连接通道在WebSocket 连接中的后续往返 WebSocket 通信都由同一台服务器来处理。

五、SignalR分布式部署

        我们可以让多台服务器上的集线器连接到一个消息队列中,通过这个消息队列完成跨服务器的消息投递。微软官方提供了用 Redis 服务器来解决 SignalR 部署在分布式环境中数据同步的方案——Redis backplane
第1步,我们通过 NuGet 安装 MicrosofAspNetCore.SignalRStackExchangeRedis。

第2步,我们在 Program.cs 中的 AddSignalR 后添加 AddStackExchangeRedis 来指定要连接的 Redis 配置

 builder,Services.AddsignalR().AddStackExchangeRedis("127.0.0.1", options => {options .Configuration,ChannelPrefix = "Test";});

六、SignalR身份认证

       集线器允许任意客户端连接,这样做有安全问题,应该对连接进行验证,只有通过验证的用户才能连接集线器。SignalR 支持验证和授权机制,我们同样可以用Cookie、JWT 等方式进行身份信息的传递。
第1步,先在配置系统中配置一个名字为WT 的节点,然后在JWT 节点下创建 SigningKey、ExpireSeconds 两个配置项。再创建一个类 JWTOptions,类中包含对应的 SigningKey、ExpireSeconds 两个属性。
第 2步,通过 NuGet 安装 Microsoft.AspNetCore.Authentication.JwtBearer。

第 3步,编写代码对JWT 进行配置

七、部分客户端的消息推送(私聊功能)

Hub类的Groups属性为 IGroupManager 类型,它可以用于对组成员进行管理

       我们在把连接加入组中的时候,如果指定名字的组不存在,SignalR 会自动创建组。因为连接和组的关系是通过 Connectionld 建立的,所以客户端重连之后,我们就需要把连接重新加入组。
Hub类的 Clients 属性为 IHubCallerClients 类型,它可以用来对连接到当前集线器的客户端进行筛选。IHubCallerClients 类包含如下成员。

第一步: 我们在 ChatRoomHub 中增加一个发送私聊消息的 SendPrivateMessage 方法

第二步: 在前端页面增加私聊功能的界面和代码

第三步,网页端监听服务器端发送的 ReceivPrivateMessage 消息,把收到的私聊消息添加到聊天消息界面中

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 ASP.NET MVC 中使用 SignalR 实现推送功能需要以下步骤: 1. 在 Visual Studio 中创建一个 ASP.NET MVC 项目。 2. 通过 NuGet 安装 SignalR 库。 3. 创建一个 SignalR Hub 类。Hub 类是用来处理客户端和服务器之间的连接和消息传递的核心组件。 4. 在 Startup.cs 中配置 SignalR 中间件。 5. 在客户端 JavaScript 中引用 SignalR 库,并连接到 SignalR Hub。 6. 在 SignalR Hub 中定义需要推送消息方法,然后在服务器端调用该方法以向客户端发送消息。 下面是一个简单的示例: 1. 创建一个名为 ChatHub 的 SignalR Hub 类: ```csharp using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace MvcSignalR.Hubs { public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } } } ``` 2. 在 Startup.cs 中配置 SignalR 中间件: ```csharp using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MvcSignalR.Hubs; namespace MvcSignalR { public class Startup { public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) { Configuration = configuration; } public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSignalR(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseStaticFiles(); app.UseSignalR(routes => { routes.MapHub<ChatHub>("/chathub"); }); app.UseMvcWithDefaultRoute(); } } } ``` 3. 在客户端 JavaScript 中引用 SignalR 库,并连接到 SignalR Hub: ```javascript <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="/lib/signalr/dist/browser/signalr.js"></script> <script> var connection = new signalR.HubConnectionBuilder().withUrl("/chathub").build(); connection.start().then(function () { console.log("connected"); }).catch(function (err) { return console.error(err.toString()); }); connection.on("ReceiveMessage", function (user, message) { console.log(user + " says " + message); }); $("#sendButton").click(function () { var user = $("#userInput").val(); var message = $("#messageInput").val(); connection.invoke("SendMessage", user, message).catch(function (err) { return console.error(err.toString()); }); }); </script> ``` 4. 在 SignalR Hub 中定义需要推送消息方法,然后在服务器端调用该方法以向客户端发送消息。 在这个示例中,当客户端调用 SendMessage 方法时,服务器将向所有连接的客户端发送 ReceiveMessage 消息。 以上就是在 ASP.NET MVC 中使用 SignalR 实现推送功能的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咬口大葱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值