• SignalR 持久链接 (该功能为手机设备与后台同个用户id进行实现的,仅用signalR学习参考)


    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Threading;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Transports;
    using MY.BllModel;
    using Newtonsoft.Json;
    using Task = System.Threading.Tasks.Task;
    using MY.Logging;
    using MY.Utility;
    
    namespace SignalR.Persistent
    {
        /// <summary>
        /// 持久连接
        /// </summary>
        public partial class CharPersistent : PersistentConnection
        {
            //log类声明为局部静态是为性能考虑
            private static readonly LogHelper LogHelper = new LogHelper("SignalR.Persistent.CharPersistent");
            protected static SyncList<DeviceOnlineModel> UserModelList = new SyncList<DeviceOnlineModel>();
    
            /// <summary>
            /// 真实链接数量
            /// </summary>
            protected static int ConnectionsCount = 0;
    
            /// <summary>
            /// 接受到消息
            /// </summary>
            protected override async Task OnReceived(IRequest request, string connectionId, string data)
            {
                try
                {
                    if (string.IsNullOrEmpty(data))
                    {
                        throw new Exception("请求参数不能为空");
                    }
    
                    var json = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
                    if (!json.ContainsKey("type") || !json.ContainsKey("text"))
                    {
    
                        throw new Exception("参数{type,text}不能为空");
                    }
    
                    switch (json["type"].ToString().ToLower())
                    {
                        case "online": //设备、web上线
                            await Online(request, connectionId, json["text"].ToString());
                            break;
                        case "ng": //设备、web指令接收
                            await MsgForwarding(connectionId, data);
                            if (json["text"].ToString().ToLower() == "getall")
                            {
                                LogHelper.DebugAsync("设备返回getall时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
                            }
    
                            break;
                        case "onlineline": //获得在线列表
                            Connection.SendToWeb(connectionId,
                                new {count = ConnectionsCount, list = UserModelList}.ToJson());
                            break;
                        case "sendmsg": //中转服务器发送消息
                            ServiceSendMsg(json["userid"].ToString(), json["text"].ToString());
                            break;
                        case "appexceptionlog": //应用异常日志
                            AddException(json["text"].ToString());
                            break;
                        case "recovered": //找回设备
                        case "notice": //通知回复
                        case "getbluetooth": //取的蓝牙数据
                        case "getappblacklist": //取的应用黑名单数据
                        case "getphonebook": //取的电话簿
                        case "removeapp": //删除app
                            if (json["result"].ToString() == "1")
                            {
                                HandlePushEnd(json["text"].ToString());
                                LogHelper.DebugAsync(string.Format("特殊推送收到成功回复,回复类型:{0},json:{1}",
                                    json["type"].ToString().ToLower(), data));
                            }
                            else
                            {
                                LogHelper.DebugAsync(string.Format("特殊推送收到失败回复,回复类型:{0},json:{1}",
                                    json["type"].ToString().ToLower(), data));
                            }
    
                            break;
                        default:
                            LogHelper.DebugAsync(string.Format("服务器接收到消息【{0}】,消息内容为{1}", connectionId, data));
                            break;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.ErrorAsync("接收消息异常:" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
                    //错误指令返回
                    Connection.SendErrMsg(connectionId, ex.Message);
                }
            }
    
    
            /// <summary>
            /// 用户发送消息转发处理
            /// </summary>
            /// <param name="userid"></param>
            /// <param name="msg"></param>
            private void ServiceSendMsg(string userid, string msg)
            {
                if (string.IsNullOrEmpty(userid))
                {
                    return;
                }
    
                userid = Uri.EscapeDataString(userid);
                var entity = UserModelList.FirstOrDefaultV(q => q.UserId == userid && q.UserType == (int) UserType.AppUser);
                if (entity != null)
                {
                    //指定用户发送消息
                    Connection.Send(entity.UserConnerctionId, msg);
                }
    
                LogHelper.DebugAsync(string.Format("服务推送消息给设备用户【{0}】,消息内容为{1}", userid, msg));
            }
    
    
            /// <summary>
            /// 上线
            /// </summary>
            /// <param name="request"></param>
            /// <param name="connectionId"></param>
            /// <param name="text"></param>
            private async Task Online(IRequest request, string connectionId, string text = "")
            {
                try
                {
                    //获得用户信息
                    if (string.IsNullOrEmpty(text))
                    {
                        text = request.QueryString["userid"];
                        if (string.IsNullOrEmpty(text))
                        {
                            return;
                        }
                    }
    
                    if (string.IsNullOrEmpty(text))
                    {
                        throw new Exception("参数{text}不能为空");
                    }
    
                    var texts = text.Split('|');
                    if (texts.Length < 2)
                    {
                        throw new Exception("参数{text}异常:{"type":"online","text":"imei|usertype|sign|timestamp"}");
                    }
    
                    var userid = texts[0]; //用户
                    var usertype = 0;
                    if (!int.TryParse(texts[1], out usertype))
                    {
                        throw new Exception(
                            "参数{text}异常:{"type":"online","text":"imei|usertype|sign|timestamp"},usertype参数异常");
                    }
    
                    //存储用户
                    var model = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == connectionId);
                    if (model == null)
                    {
                        userid = Uri.EscapeDataString(userid);
                        UserModelList.Add(new DeviceOnlineModel()
                            {UserConnerctionId = connectionId, UserId = userid, UserType = usertype});
                    }
    
                    //web上线
                    if (usertype == (int) UserType.SysWebUser)
                    {
                        //验证请求地址是否合法
                        var hosts = ConfigurationManager.AppSettings["SignalRClientWebHost"];
                        if (!string.IsNullOrEmpty(hosts))
                        {
                            var arrHost = hosts.Split(',');
                            var origin = request.Headers["Origin"];
                            //非法地址直接断开
                            if (!arrHost.Contains(origin))
                            {
                                LogHelper.ErrorAsync("非法连接,请求来源:" + request.Headers.ToJson() + ",连接数据:" + text);
                                await ServiceDisconnect(connectionId);
                                return;
                            }
                        }
    
    
                        //获得要发送的链接id列表
                        var sendEntity = GetRrelatedSendList(connectionId).FirstOrDefault();
                        if (sendEntity != null)
                        {
                            //记录日志
                            LogHelper.DebugAsync("WEB用户getall时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
                            //推送获取设备信息指令
                            await Task.Run(() => Connection.SendToDevice(sendEntity.UserConnerctionId,
                                JsonConvert.SerializeObject(new {type = "ng", text = "getall",})));
    
                            //告知web该设备在线
                            //await Task.Run(() => Connection.SendToWeb(connectionId, "Online"));
                        }
                        else
                        {
                            //告知web该设备不在线
                            await Task.Run(() => Connection.SendToWeb(connectionId, "NoOnline"));
                        }
    
                        //记录日志
                        LogHelper.DebugAsync("WEB用户【" + Uri.UnescapeDataString(userid) + "】上线了");
                    }
                    //设备上线
                    else
                    {
                        //验证请求是否合法
                        if (texts.Length != 4)
                        {
                            throw new Exception(
                                "参数{text}异常:{"type":"online","text":"imei|usertype|sign|timestamp"}");
                        }
    
                        //检测是否合法
                        var signalRKey = ConfigurationManager.AppSettings["SignalRKey"];
                        if (signalRKey != "")
                        {
                            var sign = texts[2];
                            var timestamp = texts[3];
                            var sign2 = MY.Utility.Encryption.EncryptMd5($"{userid}|{usertype}|{timestamp}|{signalRKey}");
                            if (!sign.Equals(sign2, StringComparison.OrdinalIgnoreCase))
                            {
                                LogHelper.ErrorAsync("非法连接 ,连接数据:" + text);
                                await ServiceDisconnect(connectionId);
                                return;
                            }
                        }
    
                        //存在网站用户登陆
                        bool onlineCnt =
                            UserModelList.AnyV(o => o.UserId == userid && o.UserType == (int) UserType.SysWebUser);
    
                        if (onlineCnt)
                        {
                            //推送获取设备信息指令
                            await Task.Run(() => Connection.SendToDevice(connectionId,
                                JsonConvert.SerializeObject(new {type = "ng", text = "getall",})));
                        }
    
                        //记录日志
                        LogHelper.DebugAsync("设备用户【" + Uri.UnescapeDataString(text) + "】上线了");
    
                        //同步设备在线情况
                        SyncDeviceOnlineSituation();
    
                        //写入设备上线记录
                        AddDeviceConnectLog(userid, connectionId, 1, "设备上线");
                    }
                }
                catch (Exception e)
                {
                    LogHelper.ErrorAsync("连接上线异常【" + text + "】:" +
                                         (e.InnerException != null ? e.InnerException.Message : e.Message));
                    LogHelper.ErrorAsync("异常堆栈:" + e.ToJson());
    
                    //错误指令返回
                    Connection.SendErrMsg(connectionId, e.Message);
                    ServiceDisconnect(connectionId, false);
                }
            }
    
    
    
            /// <summary>
            /// 连接断开 
            /// </summary>
            protected override async Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
            {
                Interlocked.Decrement(ref ConnectionsCount);
                try
                {
                    DeviceOnlineModel model = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == connectionId);
    
    
                    if (model != null)
                    {
                        //设备离线
                        if (model.UserType == (int) UserType.AppUser)
                        {
                            var sendEntitys = GetRrelatedSendList(connectionId);
                            if (sendEntitys != null)
                            {
                                foreach (var sendEntity in sendEntitys)
                                {
                                    List<DeviceOnlineModel> onlineList = UserModelList.WhereV(o =>
                                        o.UserId == model.UserId && o.UserType == (int) UserType.AppUser).ToList();
    
                                    if (onlineList.Count() == 1)
                                    {
                                        //推送设备离线
                                        await Task.Run(() =>
                                            Connection.SendToWeb(sendEntity.UserConnerctionId, "NoOnline"));
                                    }
                                }
                            }
    
                            LogHelper.DebugAsync("设备用户【" + Uri.UnescapeDataString(model.UserId + "|" + model.UserType) +
                                                 "】下线了");
    #pragma warning disable 4014
    
                            //同步设备在线情况
                            SyncDeviceOnlineSituation();
    
                            //写入设备下线记录
                            AddDeviceConnectLog(model.UserId, connectionId, 2, "设备下线");
    #pragma warning restore 4014
                        }
                        else
                        {
                            LogHelper.DebugAsync("WEB用户【" + Uri.UnescapeDataString(model.UserId + "|" + model.UserType) +
                                                 "】下线了");
                        }
    
    
                        UserModelList.Remove(model);
    
                    }
                }
                catch (Exception e)
                {
                    LogHelper.ErrorAsync("连接断开异常【" + connectionId + "】:" +
                                         (e.InnerException != null ? e.InnerException.Message : e.Message));
                    LogHelper.ErrorAsync("异常堆栈:" + e.ToJson());
                }
    
                //默认调用
                await base.OnDisconnected(request, connectionId, stopCalled);
            }
    
    
            /// <summary>
            /// 连接创建
            /// </summary>
            protected override async Task OnConnected(IRequest request, string connectionId)
            {
                Interlocked.Increment(ref ConnectionsCount);await Online(request, connectionId);
                await base.OnConnected(request, connectionId);
            }
    
    
            /// <summary>
            /// 重新连接
            /// </summary>
            /// <param name="request"></param>
            /// <param name="connectionId"></param>
            /// <returns></returns>
            protected override async Task OnReconnected(IRequest request, string connectionId)
            {
                //ConnectionsCount++;
                await Online(request, connectionId);
                await base.OnReconnected(request, connectionId);
            }
    
    
            /// <summary>
            /// 消息转发,通过当前消息用户链接id找到对应的用户链接id
            /// </summary>
            /// <param name="userConnerctionId"></param>
            /// <param name="data"></param>
            private async Task MsgForwarding(string userConnerctionId, string data)
            {
                if (string.IsNullOrEmpty(userConnerctionId))
                {
                    return;
                }
    
                //获得要发送的链接id列表
                var sendEntitys = GetRrelatedSendList(userConnerctionId);
                if (sendEntitys != null)
                {
                    foreach (var model in sendEntitys)
                    {
                        if (model != null)
                        {
                            //指定用户发送消息
                            await Connection.Send(model.UserConnerctionId, data);
    
                            LogHelper.DebugAsync($"服务器转发消息给用户:{model.UserId}|{model.UserType},内容为:{data}");
                        }
                    }
                }
    
                //记录用户记录
                DeviceOnlineModel entity = UserModelList.FirstOrDefaultV(o => o.UserConnerctionId == userConnerctionId);
    
    
                if (entity != null)
                {
                    //指令发送成功后回复发送端发送成功
                    if (entity.UserType == (int) UserType.SysWebUser)
                    {
                        var dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
                        if (dic["text"].Equals("restart")
                            || dic["text"].Equals("shutdown")
                            || dic["text"].Equals("resumedefault"))
                        {
                            await Connection.Send(entity.UserConnerctionId, "MainSendOK");
                        }
                    }
    
                    LogHelper.DebugAsync("服务器接收到【" + (entity.UserType == (int) UserType.SysWebUser ? "WEB" : "设备") +
                                         "】用户【" + entity.UserId + "】,消息内容为:" + data);
                }
            }
    
    
    
            /// <summary>
            /// 获得发送连接id列表
            /// </summary>
            /// <param name="userConnerctionId"></param>
            /// <returns></returns>
            public List<DeviceOnlineModel> GetRrelatedSendList(string userConnerctionId)
            {
    
                //发送消息的用户
                var entity = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == userConnerctionId);
                if (entity != null)
                {
                    var usertype = entity.UserType == (int) UserType.AppUser
                        ? (int) UserType.SysWebUser
                        : (int) UserType.AppUser;
                    //要推送消息的用户
                    var sendEntitys = UserModelList.WhereV(q => q.UserId == entity.UserId && q.UserType == usertype)
                        .ToList();
                    return sendEntitys;
                }
    
                return null;
            }
    
    
            /// <summary>
            /// 服务器强制断开连接
            /// </summary>
            /// <param name="connectionId"></param>
            /// <param name="isSendErrMsg"></param>
            private async Task ServiceDisconnect(string connectionId, bool isSendErrMsg = true)
            {
                await GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>().GetConnections()
                    .First(o => o.ConnectionId == connectionId).Disconnect();
                if (isSendErrMsg)
                {
                    //错误指令返回
                    Connection.SendErrMsg(connectionId, "非法连接,强制断开");
                }
            }
    
        }
    
    }

    继SignalR 持久链接 Web客户端

  • 相关阅读:
    MySql数据库水平扩展过程
    (转)MySQL数据库水平切分的实现原理解析
    SVN安装使用
    servlet基础
    数据库读写分离的性能分析
    java的可变长参数
    java消息服务
    static/final成员与多态
    商业软件与开源软件
    托管堆
  • 原文地址:https://www.cnblogs.com/zengtianli/p/12746504.html
Copyright © 2020-2023  润新知