.NET Core C#系列之SignalR全链路websocket发布订阅B2B模式

问题背景:我有两个系统A和B,WEB客户端调用系统A的API接口,B系统和硬件进行socket连接交互。A系统也可以直接调用B系统的api接口。但是B不能调用A系统。

A系统是主系统,

B系统是子服务,硬件和B系统是一对一socket消息推送。

此时我想让硬件推送的设备状态由B系统再推送到A系统。

通过 B系统做为一个桥梁,最终实现 A<--B<--硬件。

此时你会说,直接用消息队列mq不就可以了吗?是的,这个队列可以解决目前的问题,但是对于小团队项目,研发人员不多的情况下。每增加一个中间件或者应用软件,都会增加维护的成本。况且,AB两个系统都增加了SignalR服务端。所以,用现有的基础设施,增加自己想要的功能,让一个工具发挥到极致,才是用兵之道。

画个图说明一下:

3f6eb43b5b608318cd1092b925993246.png

实现代码很简单:

系统AB的SignalR的服务端写法都是一样的,详细见微软文档:

https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-7.0&tabs=visual-studio

我写了一个简单的SignalR的服务端demo如下:

using Microsoft.AspNetCore.SignalR;


namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
    /// <summary>
    /// 失去连接
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    public override Task OnDisconnectedAsync(Exception exception)
    {       
        return base.OnDisconnectedAsync(exception);
    }
    /// <summary>
    /// 连接上
    /// </summary>
    /// <returns></returns>
    public override Task OnConnectedAsync()
    {
        return base.OnConnectedAsync();
    }
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <returns></returns>
    public async Task SendMessage(string user, string message)
     {
         await Clients.All.SendAsync("ReceiveMessage", user, message);
     }
    }
}

必须将 SignalR 服务器配置为将 SignalR 请求传递给 SignalR。将以下突出显示的代码添加到 Program.cs 文件。

using SignalRChat.Hubs;


var builder = WebApplication.CreateBuilder(args);


// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();


var app = builder.Build();


// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}


app.UseHttpsRedirection();
app.UseStaticFiles();


app.UseRouting();


app.UseAuthorization();


app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");


app.Run();

服务端大致就是这个写法,不写太具体了。具体的去参看微软文档吧。

👆上面核心的代码就这3行:

using SignalRChat.Hubs;
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chatHub");

重点来了,我在微软文档没有找到 netcore api 的SignalR 客户端的demo。只找到了 wpf 、winfom 这样的客户端demo。很显然,这需要做相关改造工作。

我要实现一个 netcore api 的SignalR 客户端的demo。

在Program.cs里面写上如下代码:

当然,你也可以抽离出来。

//连接的时候传递参数Param
            var param = new Dictionary<string, string> {
                { "SubscribeSIP", "1" }
            };
            HubConnection connection = new HubConnectionBuilder()
              .WithUrl("你的服务端连接地址")
              , option => { option.Headers = param; })
              .WithAutomaticReconnect(new RandomRetryPolicy())
              .Build();
              //连接的函数
             ConnectWithRetryAsync(connection, CancellationToken.None);      
             //监听服务端推来的消息
            connection.On<string, string>("Notification", async (user, message) =>
            {
                await clientCallBack.Notification(user, message);
                Console.WriteLine(message);
            });
            //调用服务端的 SendMessage函数
            connection.InvokeAsync("SendMessage","autoChang","hello");
/// <summary>
        /// SignalR Cline首次连接,如SignalR Server不在线会持续连接
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public static async Task<bool> ConnectWithRetryAsync(HubConnection connection, CancellationToken token)
        {
            while (true)
            {
                try
                {
                    Console.WriteLine(" SignalR 首次连接中....");
                    await connection.StartAsync(token);
                    if (connection.State == HubConnectionState.Connected)
                    {
                        Console.WriteLine(" SignalR 首次连接成功....");
                        return true;
                    }
                }
                catch when (token.IsCancellationRequested)
                {
                    return false;
                }
                catch
                {
                    if (connection.State == HubConnectionState.Disconnected)
                    {
                        Console.WriteLine("SignalR 首次连接失败,5秒之后重试");
                        await Task.Delay(5000);
                    }
                }
            }
        }
/// <summary>
    /// 连接成功之后,再次断开的重试连接策略
    /// </summary>
    public class RandomRetryPolicy : IRetryPolicy
    {
        private readonly Random _random = new Random();


        public TimeSpan? NextRetryDelay(RetryContext retryContext)
        {
            var time = _random.NextDouble() * 10;
            Console.WriteLine($" SignalR 在{time}秒后重试连接");
            return TimeSpan.FromSeconds(time);
        }
    }

客户端可以携带参数,

var param = new Dictionary<string, string> {
                { "SubscribeSIP", "1" }
            };

服务端收到参数后,进行解析

/// <summary>
    /// 连接上
    /// </summary>
    /// <returns></returns>
    public override Task OnConnectedAsync()
    {
        var isSubscribeSIP = Context.GetHttpContext().Request.Headers["SubscribeSIP"].ObjToInt() == 1 ? true : false;
        var identifier = Context.UserIdentifier;
        _logger.LogInformation($"用户:{identifier}->连接服务成功,是否订阅SIP设备信息:{isSubscribeSIP}");        
        return base.OnConnectedAsync();
    }

当消息推送的时候,可以指定给订阅者推送相关信息:

/// <summary>
    /// 消息通知,给订阅sip设备者,发送设备信息
    /// </summary>
    /// <param name="deviceInfoDto"></param>
    public async void AddMessageToSipDeviceInfo(WSsipDeviceInfoDto deviceInfoDto)
    {
        var clients = SignalRClientList.Where(d => d.IsSubscribeSIP).ToList();
        if (clients == null) return;
        foreach (var client in clients)
        {
            deviceInfoDto.SignalrUserId = client.Signalr_userId;
            client.ConnectionIds.ForEach(x => _hubContext.Clients.Client(x).SendAsync(SignalREvent.SipDeviceInfo, deviceInfoDto));
        }
    }

以上是技术要领,学会思想。实践很快的。更多的建议是去看微软文档,文档写的很明白。无非就是wpf  winfom 客户端 如何转换成 netcore api的客户端的思想。更多是生命周期的注册,如何实例化等。

好了,今天的分享就到这里。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebSockets 是一种在客户端和服务器之间建立持久性连接的通信协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。 要实现发布-订阅模式WebSocket,你可以使用以下步骤: 1. 建立 WebSocket 连接:客户端通过向服务器发起 WebSocket 连接来建立与服务器的通信通道。 2. 发布消息:服务器可以将消息发送到所有订阅了特定频道或主题的客户端。这意味着服务器会向所有订阅该频道的客户端发送相同的消息。 3. 订阅频道:客户端可以向服务器发送一个订阅请求,指示服务器订阅特定的频道或主题。当服务器有关于该频道的新消息时,它会将消息推送给所有订阅了该频道的客户端。 4. 取消订阅:客户端也可以向服务器发送取消订阅的请求,以停止接收特定频道的消息。 在实际应用中,你可以使用不同的库或框架来实现 WebSocket 的发布-订阅模式,例如: - WebSocket API: 原生 JavaScript 提供了 WebSocket API,你可以使用它来创建 WebSocket 连接,并发送和接收消息。 - Socket.IO: Socket.IO 是一个流行的 WebSocket 库,它提供了跨浏览器的双向通信。它支持发布-订阅模式,并且还提供了其他功能,如房间管理、实时事件等。 - MQTT over WebSocket: MQTT 是一种轻量级的消息队列传输协议,它可以在 WebSocket 上运行。使用 MQTT over WebSocket,你可以实现高效的发布-订阅模式。 这只是一些实现 WebSocket 发布-订阅模式的方式,具体选择取决于你的需求和技术栈。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值