C# 实现WebSocket和SignalR通信
使用背景
首先说一下用websocket的背景,因为公司新开发了小程序的业务,需要用的通讯即服务器推送消息给小程序。
一开始项目中使用的是 SignalR 因为小程序不支持所以更改使用websocket
具体实现
首先要在NuGet导入“Fleck”包,需 .NET Framework 4.5及以上。
然后定义一个PushHelper的一个推送帮助类:
ws://0.0.0.0:3301 这个是本机地址,然后端口名是3301 这个不能占用。
然后websocket这个地址是可以增加自定义参数的,如:?id=“1”&name=“张三”
本项目使用的是groupname和groupvalue这两个参数;
具体实现可以看代码的封装。
using Coldairarrow.Util.Helper; using Fleck; using Microsoft.AspNet.SignalR; using System; using System.Collections.Generic; using System.Linq; namespace Coldairarrow.Util { public class PushHelper { /// <summary> /// 所有的连接 /// </summary> public static List<WebsocketDB> allSockets = new List<WebsocketDB>() { }; //public static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>(); /// <summary> /// webscoket服务端实例 /// </summary> public static WebSocketServer server = new WebSocketServer("ws://0.0.0.0:3301"); //通知前端刷新页面 public static void ReloadPage(string AuctionId) { Send("ReloadPage", AuctionId, "reload-" + AuctionId); } /// <summary> /// 推送发言 /// </summary> /// <param name="MarkId"></param> /// <param name="ajaxResult"></param> public static void AuctioneerSpeakAuction(string MarkId, ChartDTO ajaxResult) { Send("Speak", MarkId, ajaxResult.ToJson()); } /// <summary> /// 初始化websocket服务 /// </summary> public static void Dosocket() { try { server.Start(socket => { var strSocket = socket.ConnectionInfo.Path.Substring(1); var dicQ = StringHelper.GetQueryString(strSocket); var groupN = dicQ["GroupName"]; var groupV = dicQ["GroupValue"]; WebsocketDB websocket = new WebsocketDB() { GroupName = groupN, GroupValue = groupV, Socket = socket }; socket.OnOpen = () => { allSockets.Add(websocket); //这是把每一个socket添加到allScokets中(表示当有一个页面连接上这个socket的时候,就会多一个socket) }; //关闭链接 socket.OnClose = () => { allSockets.Remove(websocket); //用户断开socket连接时,就把这个用户的socket移除 }; }); } catch (Exception ex) { throw; } } /// <summary> /// 封装websocket推送模板 /// </summary> /// <param name="groupName"></param> /// <param name="groupValue"></param> /// <param name="res"></param> public static void Send(string groupName, string groupValue, byte[] res) { var sockets = allSockets.Where(x => x.GroupName == groupName && x.GroupValue == groupValue).ToList(); foreach (var item in sockets) { item.Socket.Send(res); } } /// <summary> /// 封装websocket发送接口 /// </summary> /// <param name="groupName"></param> /// <param name="groupValue"></param> /// <param name="res"></param> public static void Send(string groupName, string groupValue, string res) { var sockets = allSockets.Where(x => x.GroupName == groupName && x.GroupValue == groupValue).ToList(); foreach (var item in sockets) { item.Socket.Send(res); } } } public class WebsocketDB { public string GroupName { get; set; } public string GroupValue { get; set; } /// <summary> /// 连接对象 /// </summary> public IWebSocketConnection Socket { get; set; } } }
定义之后就可以在项目启动时调用一下,这里以mvc为例:
在RouteConfig.cs下面进行调用。
前端代码:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <textarea id="textarea" style="height: 500px; width: 300px;"></textarea> <input type="button" id="send" onclick="send()" value="发送"> <input type="text" id="message"> <script type="text/javascript"> //检查浏览器是否支持WebSocket if (!window.WebSocket) { console.log('您的浏览器不支持WebSocket,请选择其他的浏览器再尝试连接服务器'); } var el = document.getElementById("textarea"); var wsClientSp2 = new WebSocket('ws://localhost:3301?GroupName=Speak&GroupValue=1410879750406148096'); /* var wsClient = new WebSocket('ws://localhost:7181/add');//方法2 */ wsClientSp2.open = function (e) { el.value += "连接成功!\r\n"; } wsClientSp2.onclose = function (e) { el.value += "连接断开!\r\n"; } wsClientSp2.onmessage = function (e) { /* console.log(wsClient);*/ el.value += "接收消息:" + e.data + "\r\n"; } wsClientSp2.onerror = function (e) { el.value += "连接失败!原因【" + e.data + "】\r\n"; } function send() { //var oText = document.getElementById("message"); //wsClient.send(oText.value); } </script> </body> </html>
最后上一个成品图
SignalR
1,引用一下nuget包(不知道是哪个了。。那就全部引用吧~)
2,添加添加一个继承hub的类,代码如下:
/// <summary> /// Signalr推送的类 /// </summary> [HubName("send")] public class Sends : Hub { public static List<UserDetail> ConnectedUsers = new List<UserDetail>(); //前端连接后台,继承hub public override Task OnConnected() { var groupName = Context.QueryString["groupname"]; if (string.IsNullOrEmpty(groupName)) { return base.OnConnected(); } var connectionId = Context.ConnectionId; Groups.Add(connectionId, groupName); //判断是否存在连接 存在删除 if (ConnectedUsers.Where(x => x.ConnectionId == connectionId).Count() > 0) { ConnectedUsers.RemoveAll(x => x.ConnectionId == connectionId); } ConnectedUsers.Add(new UserDetail() { ConnectionId = connectionId, AcutionId = groupName }); //获取当前会场在线人数 int AuctionCount = ConnectedUsers.Where(x => x.AcutionId == groupName).Count(); GlobalHost.ConnectionManager.GetHubContext<Sends>().Clients.Group(groupName).OnlineCount(AuctionCount); Clients.Caller.OnlineCount(AuctionCount); return base.OnConnected(); } /// <summary> /// 离线方法 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { var groupName = Context.QueryString["groupname"]; var connectionId = Context.ConnectionId; //判断是否存在连接 存在删除 if (ConnectedUsers.Where(x => x.ConnectionId == connectionId).Count() > 0) { ConnectedUsers.RemoveAll(x => x.ConnectionId == connectionId); } if (ConnectedUsers != null && ConnectedUsers.Count > 0) { //获取当前会场在线人数 int AuctionCount = ConnectedUsers.Where(x => x.AcutionId == groupName).Count(); GlobalHost.ConnectionManager.GetHubContext<Sends>().Clients.Group(groupName).OnlineCount(AuctionCount); } return base.OnDisconnected(stopCalled); } public void OnSyncTime(string auctionId, string dateTime) { //调用所有客户端的sen方法 Clients.All.SyncTime(auctionId, dateTime); } } public class UserDetail { /// <summary> /// 连接ID /// </summary> public string ConnectionId { get; set; } public string UserID { get; set; } public string UserName { get; set; } /// <summary> /// 会场ID /// </summary> public string AcutionId { get; set; } /// <summary> /// 登录时间 /// </summary> public DateTime LoginTime { get; set; } }
3,然后教一下大家如何使用
下面第一个红框是signalR的通知,第二个是socket通知的使用方法。
4,最关键的一步骤,就是让整个程序进行初始化。如果是.net core 那直接在Startup.cs添加I一下代码,如果是.net fromwork 需要添加一个SignalrConfig.cs文件 同样,代码如下:
using Microsoft.Owin; using Owin; using Microsoft.Owin.Cors; using Microsoft.AspNet.SignalR; [assembly: OwinStartup(typeof(Web.SignalrConfig))] namespace Web { public class SignalrConfig { public void Configuration(IAppBuilder app) { app.Map("/signalr", map => { //SignalR允许跨域调用 map.UseCors(CorsOptions.AllowAll); HubConfiguration config = new HubConfiguration() { //启用JSONP跨域 EnableJSONP = true, }; map.RunSignalR(config); }); //WebApi允许跨域调用 app.UseCors(CorsOptions.AllowAll); } } }
我是一个不断学习和成长的黄金程序员,欢迎评论与我交流技术问题。
欢迎评论(期待ing)
从前慢,车马慢。
一生只爱一个人。
分类:
asp.net
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?