24. 即时通讯
24.1 什么是即时通讯
即时通讯(Instant messaging,简称 IM)通常是指互联网上用以进行实时通讯的系统,允许两人或多人使用网络即时的传递文字信息、文档、语音与视频交流。
即时通讯不同于 e-mail 在于它的交谈是实时的。大部分的即时通讯服务提供了状态信息的特性 ── 显示联络人名单,联络人是否在线上与能否与联络人交谈。
在互联网上目前使用较广的即时通讯服务包括 Windows Live Messenger、AOL Instant Messenger、skype、Yahoo! Messenger、NET Messenger Service、Jabber、ICQ 与 QQ 等。
24.2 即时通讯应用场景
即时通讯应用场景非常广泛,需要实时交互消息的都需要。如:
- 聊天工具:QQ、WeChat、在线客服等
- 手游网游:王者荣耀、魔兽等
- 网络直播:腾讯课堂、抖音直播等
- 订单推送:美团、餐饮下单系统等
- 协同办公:公司内部文件分享、工作安排、在线会议等。
以上只是列举了比较常用的应用场景,但即时通讯的作用远不止于此。
文档紧急编写中,可以先看官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-5.0
24.3 关于 SignalR
即时通讯技术实现是复杂且过于底层化,所以微软为了简化即时通讯应用程序,开发出了一个强大且简易使用的通信库:SignalR
,通过该库我们可以轻松实现类似 QQ、微信这类 IM 聊天工具,也能快速实现消息推送、订单推送这样的系统。
24.3.1 微软官方介绍
ASP.NET Core SignalR 是一种开放源代码库,可简化将实时 web 功能添加到应用程序的功能。 实时 web 功能使服务器端代码可以立即将内容推送到客户端。
适用于 SignalR :
- 需要从服务器进行高频率更新的应用。 示例包括游戏、社交网络、投票、拍卖、地图和 GPS 应用。
- 仪表板和监视应用。 示例包括公司仪表板、即时销售更新或旅行警报。
- 协作应用。 协作应用的示例包括白板应用和团队会议软件。
- 需要通知的应用。 社交网络、电子邮件、聊天、游戏、旅行警报和很多其他应用都需使用通知。
目前 SignalR
已经内置在 .NET 5 SDK
中。同时 SignalR
支持 Web、App、Console、Desktop
等多个应用平台。
24.4 注册 SignalR
服务
在 Furion
框架中,任何服务功能都需要先注册后再使用,SignalR
也不例外。只需要在 Startup.cs
中添加注册即可:
using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;namespace Furion.Web.Core{ public sealed class Startup : AppStartup { public void ConfigureServices(IServiceCollection services) { // 其他代码... // 添加即时通讯 services.AddSignalR(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 其他代码... app.UseEndpoints(endpoints => { // 注册集线器 endpoints.MapHubs(); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } }}
24.5 SignalR
长连接和集线器
SignalR
包含两种用于在客户端和服务器之间进行通信的模型:持久性连接
和 集线器
中心。
25.5.1 持久性连接
连接表示用于发送单接收方、分组或广播消息的简单终结点。 持久性连接
(在 .NET 代码中由 PersistentConnection 类表示,在 ASP.NET Core SignalR 中 ,PersistentConnection 类已被删除。) 使开发人员能够直接访问 SignalR
公开的低级别通信协议。 使用基于连接的 Api (如 Windows Communication Foundation)的开发人员将对使用连接通信模型非常熟悉。
24.5.2 集线器
集线器是一种基于连接 API 构建的更高级别管道,它允许客户端和服务器直接调用方法。 SignalR
就像魔术一样处理跨机器边界的调度,使客户端能够像本地方法一样轻松地调用服务器上的方法,反之亦然。 如果开发人员已使用远程调用 (如 .NET 远程处理),则将对使用中心通信模型非常熟悉。 使用集线器还可以将强类型参数传递给方法,从而启用模型绑定。
想了解更多关于 持久性连接
和 集线器中心
可查阅 SignalR 官方文档
24.6 集线器 Hub
定义
在本章节中主要推荐使用集线器通信模型方式。这里主要说明 Hub
定义,如果无法理解该通信模型的作用也没关系,接下来的例子会带大家慢慢熟悉并使用。
24.6.1 两种定义方式
定义集线器只需要继承 Hub
或 Hub<TStrongType>
泛型基类即可,如:
Hub
方式
using Furion.InstantMessaging;using Microsoft.AspNetCore.SignalR;namespace Furion.Core{ /// <summary> /// 聊天集线器 /// </summary> public class ChatHub : Hub { // 定义一个方法供客户端调用 public Task SendMessage(string user, string message) { // 触发客户端定义监听的方法 return Clients.All.SendAsync("ReceiveMessage", user, message); } }}
Hub<TStrongType>
类型方式
public interface IChatClient{ Task ReceiveMessage(string user, string message);}
public class StronglyTypedChatHub : Hub<IChatClient>{ // 定义一个方法供客户端调用 public async Task SendMessage(string user, string message) { // 触发客户端定义监听的方法 await Clients.All.ReceiveMessage(user, message); }}
通过使用 Hub<IChatClient>
可以对客户端方法进行编译时检查。 这可以防止由于使用神奇字符串而导致的问题,因为 Hub<T>
只能提供对在接口中定义的方法的访问。
24.6.2 [MapHub]
配置连接地址
在 SignalR
库中要求每一个公开的集线器都需要配置客户端连接地址,所以,Furion
框架提供了更加 [MapHub]
配置,如:
using Furion.InstantMessaging;using Microsoft.AspNetCore.SignalR;using System;using System.Threading.Tasks;namespace Furion.Core{ /// <summary> /// 聊天集线器 /// </summary> [MapHub("/hubs/chathub")] public class ChatHub : Hub { // ... }}
SignalR
原生配置方式在 Furion
中推荐使用 [MapHub]
方式配置集线器客户端连接地址,当然也可以使用 SignalR
提供的方式,如在 Startup.cs
配置:
public sealed class Startup : AppStartup{ // 其他代码 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 其他代码... app.UseEndpoints(endpoints => { // 注册集线器 endpoints.MapHub<ChatHub>("/hubs/chathub"); }); }}
24.6.3 Hub
注册更多配置
有些时候,我们需要注册 Hub
时配置更多参数,比如权限、跨域等,这时只需要在 Hub
派生类中编写以下静态方法即可:
using Furion.InstantMessaging;using Microsoft.AspNetCore.SignalR;using System;using System.Threading.Tasks;namespace Furion.Core{ [MapHub("/hubs/chathub")] public class ChatHub : Hub { // 其他代码 public static void HttpConnectionDispatcherOptionsSettings(HttpConnectionDispatcherOptions options) { // 配置 } public static void HubEndpointConventionBuilderSettings(HubEndpointConventionBuilder Builder) { // 配置 } }}
以上配置等价于 SignalR
在 Startup.cs
中的配置:
app.UseEndpoints(endpoints =>{ var builder = endpoints.MapHub<ChatHub>("/hubs/chathub", options => { // 配置 });});
24.7 服务端和客户端双工通信
24.7.1 触发所有客户端代码
Clients.All.客户端方法(参数);
24.7.2 触发调用者客户端
Clients.Caller.客户端方法(参数);
24.7.3 触发除了调用者以外的客户端
Clients.Others.客户端方法(参数);
24.7.4 触发特定用户客户端
Clients.User("用户").客户端方法(参数);
24.7.5 触发多个用户客户端
Clients.Users("用户","用户2",...).客户端方法(参数);
24.7.6 触发分组内客户端
Clients.Group("分组").客户端方法(参数);
24.7.7 触发多个分组客户端
Clients.Groups("分组","分组2",...).客户端方法(参数);
24.7.8 触发分组外的客户端
Clients.GroupExcept("分组").客户端方法(参数);
24.8 自定义用户唯一标识
默认情况下 SignalR
会为每一个链接创建 ConnectionId
,但是这个 ConnectionId
并没有和我们系统的用户绑关联起来,所以需要采用自定义 ConnectionId
,如:
public class YourUserIdProvider : IUserIdProvider{ public virtual string GetUserId(HubConnectionContext connection) { // 你如何获取 UserId,可以通过 connection.User 获取 JWT 授权的用户 }}
然后在 Startup.cs
中注册即可:
builder.Services.AddSingleton<IUserIdProvider, YourUserIdProvider>();
之后就可以通过自定义 UserId
发送消息:
Clients.User(userId).客户端方法(参数);
24.9 分组管理
24.10 各个客户端连接 API
24.10.1 Javascript
客户端
24.10.2 Typescript
客户端
在 vue3.2+
中使用
- 安装微软的
signalr typescript
客户端包,主要用于调用服务端方法,如(Hub
中的SendMessage
方法):
npm i @microsoft/signalr @types/node
- 示例代码
import { HubConnectionBuilder } from "@microsoft/signalr";<script setup lang="ts"> import { HubConnectionBuilder } from "@microsoft/signalr"; import { ref } from "vue"; const messages = ref(''); const reciveMessage = (msg: string) => { console.log("msg", msg); } //初始化signalr HubConnection对象 const connection = new HubConnectionBuilder() .withUrl("<你的signalr连接地址>")//https://localhost:7260/chatHub .build(); //启动连接并发送消息测试 connection.start() .then(() => connection.send("SendMessage", "Hello")); //注册web端方法以供后端调用 connection.on("ReciveMessage", reciveMessage); const sendMsg = async () => { console.log(messages.value); await connection.send("SendMessage", messages.value).catch(function (err) { console.log(err); }); }</script>
24.10.3 .NET
客户端
24.10.4 Java
客户端
24.11 常见例子
24.11.1 实现消息广播、推送
整理中...
24.11.2 实现聊天功能
整理中...
24.11.3 实现 你画我来猜
整理中...
24.12 反馈与建议
给 Furion 提 Issue。
想了解更多 SignalR
知识可查阅 SignalR 官方文档 或 ASP.NET Core SignalR 章节。