老寒 發表於 2025-4-17 11:05:00

SignalR实时通信,多客户端与服务端交互

<h2 id="1signalr介绍">1.SignalR介绍</h2>
<p>SignalR是一个开源的库,跨平台;让Web应用与其他应用通讯变得很简单,Web服务端可以实时的将内容推送给对应的客户端,客户端发送的信息也可以实时到其他客户端。</p>
<p>SignalR提供了一种远程过程调用(RPC)的方式,使得客户端可以调用服务器的方法,同样在服务器端的方法中也能调用客户端的方法。</p>
<h3 id="11-signalr的通信方式">1.1 SignalR的通信方式</h3>
<p>SignalR支持如下的方式实现实时通信:</p>
<ul>
<li><strong>WebSockets</strong>:是一种在单个TCP连接上进行全双工通信的协议,使得服务器和浏览器的通信更加简单,服务端可以主动发送信息。</li>
<li><strong>Server-Sent Events</strong>:SSE 与 WebSocket 作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息。WebSocket是双向的,而SSE是单向的。</li>
<li>**Long Polling(长轮询) **:和传统的轮询原理一样,只是服务端不会每次都返回响应信息,只有有数据或超时了才会返回,从而减少了请求次数。</li>
</ul>
<p>SignalR会自动选择服务器和客户端能力范围内的最佳通信方式(是不是很优秀) ,当然也可以手动指定。</p>
<h3 id="12-signalr的应用场景">1.2 SignalR的应用场景</h3>
<p>其实对于Web模式下的实时通信,SignalR用上试试,感觉还是很给力的。</p>
<ul>
<li>服务端主动推送信息;比如发送公告场景;</li>
<li>监控或看板数据实时显示;比如监控系统实时展示分布到各个客户端上的数据;</li>
<li>服务端和客户端交互;比如客服系统的聊天场景。</li>
</ul>
<h2 id="2案例展示">2.案例展示</h2>
<h3 id="21-signalr服务端展示">2.1 SignalR服务端展示</h3>
<ul>
<li>创建一个net8的webapi项目,引入nuget包:Microsoft.AspNetCore.SignalR</li>
<li>编写自己的SignalR Hub</li>
</ul>
<p><strong>hub类</strong></p>
<pre><code>        public class ChatHub : Hub
        {
                private static readonly ConcurrentDictionary&lt;string, User&gt; ChatClientDict = new(); //用户字典
                /// &lt;summary&gt;
                /// 给所有人发消息
                /// &lt;/summary&gt;
                /// &lt;param name="userId"&gt;&lt;/param&gt;
                /// &lt;param name="msg"&gt;&lt;/param&gt;
                /// &lt;returns&gt;&lt;/returns&gt;
                public async Task SendMsg(long userId, string msg)
                {
                        string sendMsg = $"用户名{Context.ConnectionId}:{msg}";

                        //服务端推送给 除自已以外 的所有客户端
                        //await Clients.Others.SendAsync("ReceiveMsg", sendMsg);

                        //服务端推送给所有客户端
                        await Clients.All.SendAsync("ReceiveMsg", sendMsg);

                }

                /// &lt;summary&gt;
                /// 给指定人员发消息
                /// &lt;/summary&gt;
                /// &lt;param name="userId"&gt;&lt;/param&gt;
                /// &lt;param name="message"&gt;&lt;/param&gt;
                /// &lt;returns&gt;&lt;/returns&gt;
                /// &lt;exception cref="ArgumentException"&gt;&lt;/exception&gt;
                public async Task SendMessageToUser(string userId, string message)
                {
                        // 确保用户ID是有效的
                        if (string.IsNullOrEmpty(userId))
                        {
                                throw new ArgumentException("Invalid user ID", nameof(userId));
                        }
                        await Clients.Client(userId).SendAsync("ReceiveToUserMsg", message);
                }

                //客户端成功连接时,会触发此方法
                public override Task OnConnectedAsync()
                {
                        var cid = Context.ConnectionId;
                        //根据id获取指定客户端
                        var client = Clients.Client(cid);
                        return Task.CompletedTask;
                }

                //客户端断开连接时,会触发此方法
                public override Task OnDisconnectedAsync(Exception? exception)
                {
                        return Task.CompletedTask;
                }

                //客户端调用服务端更新数据时,会触发此方法
                public async Task UpdateMessage(MsgInfo ReceiveMessage)
                {
                        await Clients.All.SendAsync("UpdateData", ReceiveMessage);
                }


        }
</code></pre>
<ul>
<li>
<p>业务API编写,推送消息</p>
<pre><code>IHubContext&lt;ChatHub&gt; _hubContext 定义一个hub上下文,通过这个可以获取所有客户端,并进行方法调用PushMessage,推送消息
</code></pre>
</li>
</ul>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250417103941053-1460141602.png"></p>
<p><strong>注册相关服务及管道</strong></p>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250417104420557-1032105134.png"></p>
<h3 id="22-winform客户端">2.2 winform客户端</h3>
<p><strong>客户端的核心代码:</strong></p>
<p>客户端调用服务端的chathub类中的UpdateMessage方法,将客户端数据更新到服务端</p>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250417105533840-1104524881.png"></p>
<p><strong>服务端与客户端的交互逻辑</strong></p>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250417105215441-1710779191.png"></p>
<p><strong>数据展示</strong></p>
<p><img src="https://img2024.cnblogs.com/blog/2212230/202504/2212230-20250417105812568-812831078.png"></p>
<p>案例源码地址:https://gitee.com/chenshibao/csb.-signal-r</p><br><br>
来源:https://www.cnblogs.com/chenshibao/p/18830358
頁: [1]
查看完整版本: SignalR实时通信,多客户端与服务端交互