zoukankan      html  css  js  c++  java
  • Asp.Net WebApi使用Websocket

    直接上代码

    /// <summary>
        /// WebSocket Handler
        /// </summary>
        public class QWebSocketHandler
        {
            private WebSocket _websocket;
            /// <summary>
            /// 用户名
            /// </summary>
            public string User { get; set; }
            /// <summary>
            /// webSocket 连接关闭
            /// </summary>
            public event EventHandler Closed;
            /// <summary>
            /// webSocket 连接接受信息
            /// </summary>
            public event EventHandler<string> Received;
            /// <summary>
            /// webSocket 连接成功
            /// </summary>
            public event EventHandler<string> Opened;
            /// <summary>
            /// webSocket 请求连接
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public async Task ProcessRequest(AspNetWebSocketContext context)
            {
                _websocket = context.WebSocket;
    
                var login = context.User.Identity.Name;
                User = login;
                Opened?.Invoke(this, login);
                while(true)
                {
                    var buffer = new ArraySegment<byte>(new byte[1024]);
                    var receivemsg = await _websocket.ReceiveAsync(buffer, System.Threading.CancellationToken.None);
    
                    if(receivemsg.MessageType == WebSocketMessageType.Close)
                    {
                        await _websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "connect colsed", CancellationToken.None);
                        Closed?.Invoke(this, EventArgs.Empty);
                        break;
    
                    }
                    if(_websocket.State == WebSocketState.Open)
                    {
                        string remsg = Encoding.UTF8.GetString(buffer.Array, 0, receivemsg.Count);
                        Received?.Invoke(this, remsg);
                    }
                }
            }
            /// <summary>
            /// 向当前连接发送消息
            /// </summary>
            /// <param name="msg">消息内容</param>
            /// <returns></returns>
            public async Task<bool> SendMSG(string msg)
            {
                if (_websocket == null || _websocket.State != WebSocketState.Open)
                { 
                    throw new Exception("the web socket is not connected");
                }
                var sebyte = Encoding.UTF8.GetBytes(msg);
                var sebuffer = new ArraySegment<byte>(sebyte);
    
                await _websocket.SendAsync(sebuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                return true;
            }
            /// <summary>
            /// 关闭当前webSocket连接
            /// </summary>
            public void Close()
            {
                if (_websocket == null || _websocket.State == WebSocketState.Closed || _websocket.State == WebSocketState.Aborted)
                {
                    return;
                }
    
                _websocket.Abort();
            }
        }
        /// <summary>
        /// 用户离线消息池
        /// </summary>
        public class MessagePool
        {
            /// <summary>
            /// 用户
            /// </summary>
            public string User { get; set; }
            /// <summary>
            /// 消息集合
            /// </summary>
            public ConcurrentQueue<OffMessage> MessageS { get; set; }
    
        }
        /// <summary>
        /// 用户离线消息
        /// </summary>
        public class OffMessage:MessageTemplate
        {
            /// <summary>
            /// 消息失效时间
            /// </summary>
            public DateTime ValidTime { get; set; }
    
        }
    
        /// <summary>
        /// 消息实体
        /// </summary>
        public class MessageTemplate
        {
            /// <summary>
            /// 接受消息的用户Login
            /// </summary>
            public string ToUser { get; set; }
            /// <summary>
            /// 发送消息的用户Login
            /// </summary>
            public string FromUser { get; set; }
            /// <summary>
            /// 消息内容
            /// </summary>
            public MessageContent MsgContent { get; set; }
        }
    
        /// <summary>
        /// 消息内容体实体模型
        /// </summary>
        public class MessageContent
        {
            /// <summary>
            /// 标题 
            /// </summary>
            public string Title { get; set; }
            /// <summary>
            /// 内容
            /// </summary>
            public string Content { get; set; }
            /// <summary>
            /// 日期
            /// </summary>
            public DateTime Time { get; set; }
        }
    handler
    /// <summary>
        /// webSocket服务
        /// </summary>
        public class QWebSocketService
        {
            private static ConcurrentDictionary<string, QWebSocketHandler> _websockets = new ConcurrentDictionary<string, QWebSocketHandler>();
            /// <summary>
            /// 用户离线消息池
            /// 用户上线直接发送消息给用户
            /// 离线消息仅保留3天,72小时
            /// </summary>
            private static ConcurrentQueue<MessagePool> UserMessageS = new ConcurrentQueue<MessagePool>();
            /// <summary>
            /// 连接websocket
            /// </summary>
            /// <param name="Login"></param>
            /// <param name="Token"></param>
            /// <returns></returns>
            public static HttpResponseMessage Connect(System.Web.HttpContext context, string Login)
            {
    
                //如果用户存在于连接池则更新 webSocket连接信息,否则新建连接池
    
                var handler = new QWebSocketHandler();
                handler.Received -= Socket_Received;
                handler.Received += Socket_Received;
    
                handler.Closed -= Socket_Closed;
                handler.Closed += Socket_Closed;
    
                handler.Opened -= Socket_Opened;
                handler.Opened += Socket_Opened;
    
                if (_websockets.Keys.Contains(Login))
                {
                    var inhandler = _websockets[Login];
                    inhandler.Close();
                    _websockets[Login] = handler;
                }
                else
                {
                    _websockets.TryAdd(Login, handler);
                }
                context.User = new System.Security.Principal.GenericPrincipal(new System.Security.Principal.GenericIdentity(Login), null);
    
                context.AcceptWebSocketRequest(handler);
    
                return new HttpResponseMessage(System.Net.HttpStatusCode.SwitchingProtocols);
    
    
            }
    
    
            /// <summary>
            /// 清理过期消息
            /// </summary>
            private static void ClearUserMessage()
            {
                var validuser = new ConcurrentQueue<MessagePool>();
    
                foreach (var msg in UserMessageS)
                {
                    var valid = new ConcurrentQueue<OffMessage>();
    
                    foreach (var msgcontent in msg.MessageS)
                    {
                        if ((DateTime.Now - msgcontent.ValidTime).TotalHours < 72)
                        {
                            valid.Enqueue(msgcontent);
                        }
    
                    }
                    msg.MessageS = valid;
                    if (!valid.IsEmpty)
                    {
                        validuser.Enqueue(msg);
                    }
                }
                UserMessageS = validuser;
    
            }
            /// <summary>
            /// Insert send to offline user's message in messagepool
            /// </summary>
            /// <param name="msg"></param>
            private static void AddUserMessage(MessageTemplate msg)
            {
                if (UserMessageS.Any(q => q.User == msg.ToUser))
                {
                    //存在离线用户离线消息
                    var innermsg = UserMessageS.FirstOrDefault(q => q.User == msg.ToUser);
                    OffMessage offmessage = new OffMessage()
                    {
                        ToUser = msg.ToUser,
                        FromUser = msg.FromUser,
                        MsgContent = msg.MsgContent,
                        ValidTime = DateTime.Now
                    };
                    innermsg.MessageS.Enqueue(offmessage);
                }
                else
                {
                    //不存在离线用户消息
                    OffMessage offMessage = new OffMessage()
                    {
                        MsgContent = msg.MsgContent,
                        FromUser = msg.FromUser,
                        ToUser = msg.ToUser,
                        ValidTime = DateTime.Now
                    };
                    ConcurrentQueue<OffMessage> msgs = new ConcurrentQueue<OffMessage>();
                    msgs.Enqueue(offMessage);
                    MessagePool usermessage = new MessagePool()
                    {
                        User = msg.ToUser,
                        MessageS = msgs
                    };
    
                    UserMessageS.Enqueue(usermessage);
    
    
                }
    
            }
    
            private static async Task SendOffMessage(QWebSocketHandler socket, string login)
            {
                //有离线消息则发送
                await Task.Delay(2000); //异步等待2秒发送离线消息
    
                var msgs = UserMessageS.FirstOrDefault(q => q.User == login);
                if (msgs != null)
                {
                    var sended = new ConcurrentQueue<OffMessage>();
                    foreach (var omsg in msgs.MessageS)
                    {
                        var send = await socket.SendMSG(omsg.MsgContent.ToString());
    
                        if (!send)
                        {
                            send.Equals(omsg);
                        }
                    }
                    msgs.MessageS = sended;
    
                }
    
                ClearUserMessage();//清理过期离线消息
            }
            /// <summary>
            /// 向指定用户发送消息
            /// </summary>
            /// <param name="Login"></param>
            /// <param name="msg"></param>
            /// <returns></returns>
            public static async Task<bool> SendMSG(MessageTemplate msg)
            {
                if (_websockets.Any(q => q.Key == msg.ToUser))
                {
                    var socket = _websockets[msg.ToUser];
                    if (socket == null)
                    {
                        //用户不在线,消息加入离线
                        AddUserMessage(msg);
                        return false;
                    }
                    var str = JsonConvert.SerializeObject(msg.MsgContent);
                    return await socket.SendMSG(str);
                }
                else
                {
                    //用户不在线,消息加入离线
                    AddUserMessage(msg);
                    return false;
                }
    
            }
    
            private static void Socket_Opened(object sender, string login)
            {
                //连接后,发送离线消息
                SendOffMessage((QWebSocketHandler)sender, login);
            }
            /// <summary>
            /// webSocket 接收消息
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="msg"></param>
            private static void Socket_Received(object sender, string msg)
            {
    
            }
            /// <summary>
            /// webSocket 客户端关闭
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void Socket_Closed(object sender, EventArgs e)
            {
                var socket = (QWebSocketHandler)sender;
                var csocket = _websockets.FirstOrDefault(q => q.Value == socket);
    
                _websockets.TryRemove(csocket.Key, out socket);
    
            }
        }
    
    
        public static class HttpContextExtension
        {
            public static void AcceptWebSocketRequest(this HttpContext context, QWebSocketHandler handler)
            {
                context.AcceptWebSocketRequest(handler.ProcessRequest);
            }
        }
    Service
    /// <summary>
        /// webSocket 消息管理,
        /// 请使用WebSocket协议请求:
        /// ws://server/api/msger/{login}/{token}
        /// {login}为当前用户名;{token}为当前用户登陆的有效token
        /// </summary>
        [RoutePrefix("api/msger")]
        public class MessageController : LoanAPI
        {
            private DBContext db = new DBContext();
            /// <summary>
            /// 请求webSocket连接
            /// </summary>
            /// <param name="login"></param>
            /// <param name="token"></param>
            /// <returns></returns>
            [HttpGet]
            [Route("connect/{login}/{token}")]
            [AllowAnonymous]
            public HttpResponseMessage Connect(string login, string token)
            {
                var user = db.SYS_User.FirstOrDefault(q => q.Login == login && q.Token == token);
                if (user == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Login is Not Valid");
                }
                else
                {
                    if(HttpContext.Current.IsWebSocketRequest)
                    {
                        return QWebSocketService.Connect(HttpContext.Current, login);
                    }
                    else
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Is Not WebSocekt Request");
                    }
    
                }
            }
            /// <summary>
            /// 向用户发送消息,正常的http请求
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            [HttpPost]
            [Route("send")]
            public async System.Threading.Tasks.Task<ActionResult<bool>> SendMSGAsync([FromBody] MessageTemplate msg)
            {
    
               var sended = await QWebSocketService.SendMSG(msg);
    
                return new ActionResult<bool>(sended);
            }
             
        }
    Controller

     js Common

    (function ($) {
    
        $.config = {
            url: '', //链接地址
            token: '',// 通讯key
        };
    
        $.init = function (config) {
            this.config = config;
            return this;
        };
    
        /**
         * 连接webcocket
         */
        $.connect = function () {
            var protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
            this.host = protocol + this.config.url;
            this.protocols = this.config.token;
    
            window.WebSocket = window.WebSocket || window.MozWebSocket;
            if (!window.WebSocket) { // 检测浏览器支持
                this.error('Error: WebSocket is not supported .');
                return;
            }
            this.socket = new WebSocket(this.host, [this.protocols]); // 创建连接并注册响应函数
            this.socket.onopen = function () {
                $.onopen();
            };
            this.socket.onmessage = function (message) {
                $.onmessage(message);
            };
            this.socket.onclose = function () {
                $.onclose();
                $.socket = null; // 清理
            };
            this.socket.onerror = function (errorMsg) {
                $.onerror(errorMsg);
            }
            return this;
        }
    
        /**
         * 自定义异常函数
         * @param {Object} errorMsg
         */
        $.error = function (errorMsg) {
            this.onerror(errorMsg);
        }
    
        /**
         * 消息发送
         */
        $.send = function (message) {
            if (this.socket) {
                this.socket.send(message);
                return true;
            }
            this.error('please connect to the server first !!!');
            return false;
        }
    
        $.close = function () {
            if (this.socket !== undefined && this.socket !== null) {
                this.socket.close();
            } else {
                this.error("this socket is not available");
            }
        }
    
        /**
         * 消息回調
         * @param {Object} message
         */
        $.onmessage = function (message) {
            console.log(message)
        }
    
        /**
         * 链接回调函数
         */
        $.onopen = function () {
            console.log('连接成功')
        }
    
        /**
         * 关闭回调
         */
        $.onclose = function () {
            console.log('连接关闭');
        }
    
        /**
         * 异常回调
         */
        $.onerror = function (error) {
            console.log(error);
        }
    
    })(ws = {});
  • 相关阅读:
    Vue.js-项目目录结构解析
    Vue.js-创建Vue项目(Vue项目初始化)并不是用Webstrom创建,只是用Webstrom打开
    Node.js-npm安装包目录修改
    Node.js-Webstorm2018配置nodejs
    Node.js-ReferenceError: _filename is not defined
    cas系列-自定义异常提示(五)
    cas系列-cas登出(四)
    cas系列-cas REST协议(三)
    maven引入第三方jar包
    持续api管理翻译
  • 原文地址:https://www.cnblogs.com/netlock/p/13534019.html
Copyright © 2011-2022 走看看