SignalR 实时通讯
SignalR 实时通讯
- 1.SignalR
- 1.1.SignalR 简介
- 1.2.SignalR 功能
- 1.3.传输
- 1.4.中心
- 2.服务器
- 2.1.配置中心
- 2.2.上下文对象
- 2.3.客户端对象
- 2.4.创建
- 2.5.中心功能实现
- 4.客户端
- 6.案例演示(DotNet 客户端)
1.SignalR
1.1.SignalR 简介
SignalR 是一个开放源代码库,可用于简化向应用添加实时 Web 功能。 实时 Web 功能使服务器端代码能够将内容推送到客户端。
SignalR 提供用于创建服务器到客户端远程过程调用 (RPC) 的 API。 RPC 从服务器端 .NET Core 代码调用客户端上的函数。 提供多个受支持的平台,其中每个平台都有各自的客户端 SDK。
与 ASP.NET 的其余部分一样,SignalR 是为实现高性能而构建的,也是市面上最快的实时框架之一。
跨服务器横向扩展,内置支持使用 Redis、SQL Server 或 Azure 服务总线来协调每个实例之间的消息。
1.2.SignalR 功能
- 自动处理连接管理。
- 同时向所有连接的客户端发送消息。 例如聊天室。
- 向特定客户端或客户端组发送消息。
- 对其进行缩放,以处理不断增加的流量。
- SignalR 中心协议
1.3.传输
SignalR 支持以下用于处理实时通信的技术(优先选择 WebSockets):
- WebSockets ⬇
- Server-Sent Events ⬇
- 长轮询
1.4.中心
SignalR 使用 中心 在客户端和服务器之间进行通信。
Hub 是一种高级管道,允许客户端和服务器相互调用方法。 SignalR 自动处理跨计算机边界的调度,并允许客户端调用服务器上的方法,反之亦然。 可以将强类型参数传递给方法,从而支持模型绑定。 SignalR 提供两个内置中心协议:基于 JSON 的文本协议和基于 MessagePack 的二进制协议。 与 ON 相比 JS,MessagePack 通常会创建较小的消息。 旧版浏览器必须支持 XHR 级别 2 才能提供 MessagePack 协议支持。
- 中心通过发送包含客户端方法的名称和参数的消息来调用客户端代码。
- 作为方法参数发送的对象使用配置的协议进行反序列化。
- 客户端尝试将名称与客户端代码中的方法匹配。
- 当客户端找到匹配项时,它会调用该方法并将反序列化的参数数据传递给它。
- 不支持 ECMAScript 6 以下的浏览器 ES6 to ES5
2.服务器
2.1.配置中心
中心 SignalR API 使连接的客户端能够在服务器上调用方法。 服务器定义从客户端调用的方法,客户端定义从服务器调用的方法。 SignalR 处理实现实时客户端到服务器和服务器到客户端通信所需的一切。
在 Program 中注册配置 SignalR 服务和 终结点
var builder = WebApplication.CreateBuilder(args);builder.Services.AddRazorPages();
builder.Services.AddSignalR(); // 注册 SignalR 服务
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat"); // 配置 SignalR 终结点app.Run();
2.2.上下文对象
- 类 Hub 包含一个 Context 属性,该属性包含以下 属性 及 方法:
属性 | 说明 |
---|---|
ConnectionId | 获取连接的唯一 ID(由 SignalR 分配)。 每个连接都有一个连接 ID。 |
UserIdentifier | 获取用户标识符。 默认情况下,SignalR 使用与连接关联的 ClaimsPrincipal 中的 ClaimTypes.NameIdentifier 作为用户标识符。 |
User | 获取与当前用户关联的 ClaimsPrincipal。 |
Items | 获取可用于在此连接范围内共享数据的键/值集合。 数据可以存储在此集合中,会在不同的中心方法调用间为连接持久保存。 |
Features | 获取连接上可用的功能的集合。 目前,在大多数情况下不需要此集合,因此未对其进行详细记录。 |
ConnectionAborted | 获取一个 CancellationToken,它会在连接中止时发出通知。 |
方法 | 说明 |
---|---|
GetHttpContext | 返回 HttpContext 连接的 ;如果连接未与 HTTP 请求关联, null 则返回 。 对于 HTTP 连接,请使用此方法获取 HTTP 标头和查询字符串等信息。 |
Abort | 中止连接。 |
2.3.客户端对象
- 类 Hub 包含一个 Clients 属性,该属性包含以下用于 服务器和客户端之间通信 的 属性 和 方法:
属性 | 说明 |
---|---|
All | 对所有连接的客户端调用方法 |
Caller | 对调用了中心方法的客户端调用方法 |
Others | 对所有连接的客户端调用方法(调用了方法的客户端除外) |
方法 | 说明 |
---|---|
AllExcept | 对所有连接的客户端调用方法(指定连接除外) |
Client | 对连接的一个特定客户端调用方法 |
Clients | 对连接的多个特定客户端调用方法 |
Group | 对指定组中的所有连接调用方法 |
GroupExcept | 对指定组中的所有连接调用方法(指定连接除外) |
Groups | 对多个连接组调用方法 |
OthersInGroup | 对一个连接组调用方法(不包括调用了中心方法的客户端) |
User | 对与一个特定用户关联的所有连接调用方法 |
Users | 对与多个指定用户关联的所有连接调用方法 |
表中的每个属性或方法都返回具有
SendAsync
方法的对象。 方法SendAsync
接收要调用的客户端方法的名称和任何参数。
和 方法返回 Client 的对象还包含方法
InvokeAsync
,该方法可用于等待来自客户端的结果。Caller
2.4.创建
中心继承 Hub 类,可实现 弱类型中心 和 强类型中心,这里只介绍强类型中心。
创建 IChatClient interface
public interface IChatClient
{Task ReceiveMessage(string user, string message);
}
实现强类型中心,Hub 类型为我们创建的 IChatClient interface
public class ChatHub : Hub<IChatClient>{}
2.5.中心功能实现
- 向客户端发送消息
#region 连接处理/// <summary>
/// 在连接上时
/// </summary>
/// <returns></returns>
public override async Task OnConnectedAsync()
{await SendMessageToCaller(Context.ConnectionId, "主服务连接成功!");
}/// <summary>
/// 断开连接时
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
public override Task OnDisconnectedAsync(Exception? exception)
{return base.OnDisconnectedAsync(exception);
}#endregion#region 消息发送/// <summary>
/// 将消息发送到所有连接的客户端,不排除自己
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 Clients.All 将消息发送到所有连接的客户端
/// </remarks>
/// <returns></returns>
public async Task SendMessage(string user, string message)
{await Clients.All.ReceiveMessage(user, message);
}/// <summary>
/// 将消息发送到所有连接的客户端,排除自己
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 Others 将消息发送到所有连接的客户端,排除自己
/// </remarks>
/// <returns></returns>
public async Task SendMessageToOthers(string user, string message)
{await Clients.Others.ReceiveMessage(user, message);
}/// <summary>
/// 将消息发送到指定连接的客户端
/// </summary>
/// <param name="user1"></param>
/// <param name="user2"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 User 将消息发送到指定连接的客户端
/// </remarks>
/// <returns></returns>
public async Task SendMessageToUser(string user1, string user2, string message)
{await Clients.User(user1).ReceiveMessage(user2, message);
}/// <summary>
/// 将消息发送回调用方
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 Caller 将消息发送回调用方
/// </remarks>
/// <returns></returns>
public async Task SendMessageToCaller(string user, string message)
{await Clients.Caller.ReceiveMessage(user, message);
}/// <summary>
/// 将消息发送给 GroupName 组中的所有客户端
/// </summary>
/// <param name="GroupName"></param>
/// <param name="user"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 Group 将消息发送给 GroupName 组中的所有客户端
/// </remarks>
/// <returns></returns>
public async Task SendMessageToGroup(string GroupName, string user, string message)
{await Clients.Group(GroupName).ReceiveMessage(user, message);
}/// <summary>
/// 将消息发送给 GroupName 组中的所有客户端,排除自己
/// </summary>
/// <param name="GroupName"></param>
/// <param name="user"></param>
/// <param name="message"></param>
/// <remarks>
/// 使用 Group 将消息发送给 GroupName 组中的所有客户端,排除自己
/// </remarks>
/// <returns></returns>
public async Task SendMessageToOthersInGroup(string GroupName, string user, string message)
{await Clients.OthersInGroup(GroupName).ReceiveMessage(user, message);
}
#endregion
4.客户端
- JavaScript 客户端
Internet Explorer 和其他旧版浏览器,当前版本及更高版本指的是浏览器的最新版本。
- DotNet 客户端
.NET 客户端可在 ASP.NET Core 支持的任何平台上运行,具体版本号参考微软文档说明。
- Java 客户端
需 Java 8 或更高版本。
6.案例演示(DotNet 客户端)
使用 WPF 客户端程序
<Grid><Grid.RowDefinitions><RowDefinition Height="100*" MinHeight="120" /><RowDefinition Height="auto" /><RowDefinition Height="40*" MinHeight="130" /></Grid.RowDefinitions><ListBoxName="listMessage"Background="{StaticResource DominantColor}"BorderThickness="0"ItemsSource="{Binding}"><ListBox.ItemTemplate> <DataTemplate> <StackPanel VerticalAlignment="Center" Orientation="Horizontal"><TextBlock VerticalAlignment="Center" Text="{Binding Message}" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox><GridSplitterGrid.Row="1"Height="1"HorizontalAlignment="Stretch"Background="{StaticResource BorderColor}" /><Grid Grid.Row="2" Margin="30,0"><Grid.RowDefinitions><RowDefinition Height="10" /><RowDefinition Height="*" /></Grid.RowDefinitions><Grid Grid.Row="1"><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="64" /></Grid.RowDefinitions><TextBoxx:Name="TxtNewContent"Grid.Row="0"Style="{StaticResource InputStyle}" /><ButtonGrid.Row="1"Click="Send_Click"Content="发送(S)"Style="{StaticResource SendButtonStyle}" /></Grid></Grid>
</Grid>
/// <summary>
/// 连接中心
/// </summary>
private readonly HubConnection connection;/// <summary>
/// 连接字符串
/// </summary>
readonly string connectionStr = "https://localhost:7067/chat";/// <summary>
/// 消息通知
/// </summary>
ObservableCollection<MessageEntity> messages = new ObservableCollection<MessageEntity>();public MainWindow()
{InitializeComponent();connection = new HubConnectionBuilder().WithUrl(connectionStr).WithAutomaticReconnect().Build();connection.Closed += async (error) =>{await Task.Delay(new Random().Next(0, 5) * 1000);await connection.StartAsync();};listMessage.ItemsSource = messages;Loaded += MainWindow_Loaded;
}private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{connection.On<string, string>("ReceiveMessage", (user, message) =>{this.Dispatcher.Invoke(() =>{messages.Add(new MessageEntity{Message = message,IsSend = false,});});});await StartReceiveMessage();
}private async Task StartReceiveMessage()
{try{await connection.StartAsync();userId = connection.ConnectionId;}catch (Exception ex){Console.WriteLine(ex.Message);}
}/// <summary>
/// 发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Send_Click(object sender, RoutedEventArgs e)
{try{await connection.InvokeAsync("SendMessageToOthers", userId, TxtNewContent.Text.Trim());TxtNewContent.Text = string.Empty;}catch (Exception ex){Console.WriteLine(ex.Message);}
}public class MessageEntity
{/// <summary>/// 消息/// </summary>public string Message { get; set; }/// <summary>/// 是否发送人/// </summary>public bool IsSend { get; set; }
}
图中窗口使用 WindowChrome 控件自定义过,有需要可以去看【WPF】WindowChrome 自定义窗口完美实现
SignalR 实时通讯相关推荐
- Signalr实时通讯
我们直接来干货~~~~~~觉得好推荐一下哈 研究不易 参考--https://www.jb51.net/article/133202.htm 这是基本教程 下面是重点: 如果你想允许跨域 具体代码 ...
- ASP.NET Core 基于SignalR实时通讯的前后端分离技术
环境 Visual Studio 2019 ASP.NET Core 3.1 创建项目 从菜单中选择文件>新建项目. 在创建新项目对话框中,选择ASP.NET Core Web 应用程序,然后选 ...
- Java 接受reactjs数据_[Java教程]react.js 父子组件数据绑定实时通讯
[Java教程]react.js 父子组件数据绑定实时通讯 0 2017-09-23 17:00:14 import React,{Component} from 'react'import Reac ...
- Java和C/C++程序实时通讯数据移植问题的研究
简介: 摘要:本文研究了数据存储格式中大尾小尾问题,根据此原理解决了Java程序和C/C++通讯及读取服务器端文件时的数据移植问题. 问题起源 该问题起源于笔者设计的基于Web的远程测控系统.它的基本 ...
- Node.js 切近实战(十一) 之实时通讯
2019独角兽企业重金招聘Python工程师标准>>> 今天我们主要看一下Socket.IO实时通讯,先看一下界面. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
- 用PHP和Websocket实现实时通讯
说到websocket大家一定不会陌生,WebSocket是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duplex).一开始的握手需要借助HTTP请求完成,当浏览器和服务器握 ...
- PROFINET及其同步实时通讯分析
1 概述 PROFINET实时以太网是由Profibus International(PI)组织提出的基于以太网的自动化标准.从2004年4月开 始,PI与Interbus Club总线俱乐部联 ...
- 服务器具有挂起的重新启动_ESP8266与网络服务器实时通讯
背景知识视频教程 Bootstrap 4布局:响应式单页设计viadean.com Node.js,Express,MongoDB等:2020年完整的训练营 - 国外课栈viadean.com 高 ...
- Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状...
Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状 本文主要介绍国外实时通讯行业现状,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号b ...
最新文章
- NLP(Natural Language Processing)
- 「NLP」 深度学习NLP开篇-循环神经网络(RNN)
- Java中如何实现j并发更新数据库同一条数据
- rust(54)-字符串
- python(c++)刷题+剑指offer
- opensips mysql 认证_基于ubuntu中使用mysql实现opensips用户认证的解决方法
- Spark源码分析之Task
- inovance变频器说明书参数设置_汇川(INOVANCE)MD300变频器说明书.pdf
- Linux 环境下,搭建 ZooKeeper 集群
- 第三次修正打坐的姿势
- PC端浏览器如何访问微信小程序
- 2021年焊工(初级)考试报名及焊工(初级)实操考试视频
- Redis的前前后后左左右右
- php中subtr()函数的使用方法
- vmware win7虚拟机运行异常卡顿问题解决
- buaa oo-unit3
- ArcGIS 地图切图系列之(一)切片原理解析
- 关于单片机看门狗的浅谈理解
- Python - JS逆向破解实现翻译软件
- 银联在线支付5.0.0版-仿真端