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)

 

posted @   黄金程序员  阅读(3299)  评论(2编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示