.NET 4.5 WebSocket简易聊天室、离线消息(MSMQ)

.NET 4.5简化了WebSocket的处理,不用再单独用socket去解析RFC6455的协议。
Windows .NET平台上要使用WebSocket,.NET版本不低于4.5、IIS至少8、IIS要启用WebSocket。
源码点我下载。

前端:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="jquery-3.3.1.js"></script>
    <script>
        var ws;
        $().ready(function () {
            $('#conn').click(function () {
                ws = new WebSocket('ws://' + window.location.host + '/WSHandler4.ashx?user='+$('#user').val());
                $('#list').append('<p>' + '正在连接' + '</p>');
                ws.onopen = function () {
                    $('#list').append('<p>' + '连接成功' + '</p>');
                };
                ws.onmessage = function (evt) {
                    $('#list').append('<p>' + evt.data + '</p>');
                };
                ws.onerror = function (evt) {
                    $('#tips').text(JSON.stringify(evt));
                };
                ws.onclose = function () {
                    $('#list').append('<p>已断开</p>');
                };
            });
            $('#send').click(function () {
                if (ws.readyState == WebSocket.OPEN) {
                    ws.send($('#to').val() + '|' + $('#msg').val());
                } else {
                    $('#tips').text('已断开');
                }
            });
            $('#close').click(function () {
                ws.close();
            })
        });
    </script>
</head>
<body>
    <div>
        user:<input type="text" id="user" /><input type="button" id="conn" value="连接" /><input type="button" id="close" value="断开" />
    </div>
    <div>
        msg:<input type="text" id="msg" />send to:<input type="text" id="to"/><input type="button" id="send" value="发送" />
    </div>
    <div id="tips"></div>
    <div id="list"></div>
</body>
</html>

后端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.WebSockets;

namespace MSMQ_WebSocket
{
    /// <summary>
    /// WSHandler4 的摘要说明
    /// </summary>
    public class WSHandler4 : IHttpHandler
    {
        private static bool MQCreated = false;
        private static Dictionary<string, WebSocket> CONN_POOL = new Dictionary<string, WebSocket>();

        public void ProcessRequest(HttpContext context)
        {
            //context.Response.ContentType = "text/plain";
            //context.Response.Write("Hello World");
            if (!MQCreated)
            {
                MSMQ_SRV.CreateMQ();
                MQCreated = true;
            }
            if (context.IsWebSocketRequest)
            {
                context.AcceptWebSocketRequest(ProcessChat);
            }
        }
        async Task ProcessChat(AspNetWebSocketContext context)
        {
            string user = context.QueryString["user"].ToString();
            WebSocket ws = context.WebSocket;

            if (CONN_POOL.Keys.Contains(user))
            {
                if (CONN_POOL[user] != ws)
                {
                    CONN_POOL[user] = ws;
                }
            }
            else
            {
                CONN_POOL.Add(user, ws);
            }
            Message[] msgsOffline = MSMQ_SRV.GetMessageByDestUser(user);//发送者|接收者|消息内容
            if (msgsOffline.Length > 0 && ws.State == WebSocketState.Open)
            {
                foreach (var item in msgsOffline)
                {
                    //await ws.SendAsync(GetArrSegFromStr(item.Body.ToString()), WebSocketMessageType.Text, true, CancellationToken.None);
                    await ws.SendAsync(GetArrSegFromStr(item.Body.ToString().Split('|')[0] + ":" + item.Body.ToString().Split('|')[2]), WebSocketMessageType.Text, true, CancellationToken.None);
                    MSMQ_SRV.RemoveMessage(item);
                }
            }
            while (true)
            {
                if (ws.State == WebSocketState.Open)
                {
                    ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
                    WebSocketReceiveResult result = await ws.ReceiveAsync(buffer, CancellationToken.None);
                    try
                    {
                        #region 连接关闭,删除连接池
                        if (ws.State != WebSocketState.Open)
                        {
                            if (CONN_POOL.Keys.Contains(user))
                            {
                                CONN_POOL.Remove(user);
                            }
                            break;
                        } 
                        #endregion
                        string msgs = System.Text.Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
                        string desUser = msgs.Split('|')[0];
                        string desMsg = msgs.Split('|')[1];

                        if (CONN_POOL.Keys.Contains(desUser))
                        {
                            if (CONN_POOL[desUser].State == WebSocketState.Open)
                            {
                                await CONN_POOL[desUser].SendAsync(GetArrSegFromStr(desMsg), WebSocketMessageType.Text, true, CancellationToken.None);
                            }
                        }
                        else
                        {
                            //有连接,但是断线了。MSMQ离线存储.
                            //发送者|接收者|消息内容
                            MSMQ_SRV.SendMSG(string.Format("{0}|{1}|{2}:{3}", user, desUser, DateTime.Now.ToString(), desMsg));
                        }
                    }
                    catch (Exception ex)
                    {
                        if (CONN_POOL.Keys.Contains(user))
                        {
                            CONN_POOL.Remove(user);
                        }
                    }
                }
                else
                {
                    //发送消息时已离线。退出
                    break;
                }

            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// 字符串转ArraySegment<byte>,用于WebSocket发送消息
        /// </summary>
        /// <param name="text">要转换的文本</param>
        /// <returns></returns>
        ArraySegment<byte> GetArrSegFromStr(string text)
        {
            return new ArraySegment<byte>(System.Text.Encoding.UTF8.GetBytes(text));
        }
        /// <summary>
        /// ArraySegment<byte>转字符串,用于消息队列存储
        /// </summary>
        /// <param name="text">要转换的ArraySegment对象</param>
        /// <returns></returns>
        string GetStrFromArrSeg(ArraySegment<byte> arrSeg)
        {
            return System.Text.Encoding.UTF8.GetString(arrSeg.Array);
        }
    }
}

离线消息处理(消息队列msmq)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Messaging;

namespace MSMQ_WebSocket
{
    public class MSMQ_SRV
    {
        public static void CreateMQ()
        {
            MessageQueue mq = null;
            string path = @".\private$\mqDemo4";
            if (MessageQueue.Exists(path))
            {
                mq = new MessageQueue(path);
            }
            else
            {
                mq = MessageQueue.Create(path);
            }
            mq.SetPermissions("Anonymous LogOn", MessageQueueAccessRights.FullControl);
            mq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
            mq.SetPermissions("Administrator", MessageQueueAccessRights.FullControl);
            System.Diagnostics.Debug.WriteLine("mqDemo4建立成功");
        }
        public static void SendMSG(String text)
        {
            Message msg = new Message()
            {
                Body = text,
                Formatter = new XmlMessageFormatter(new Type[] { typeof(string) })
            };
            MessageQueue mq = new MessageQueue(@"FormatName:Direct=TCP:127.0.0.1\private$\mqDemo4");
            mq.Send(msg);
        }
        /// <summary>
        /// 根据接收者获取队列
        /// </summary>
        /// <param name="destUser"></param>
        /// <returns></returns>
        public static Message[] GetMessageByDestUser(string destUser)
        {
            string path = @".\private$\mqDemo4";
            MessageQueue mq = new MessageQueue()
            {
                Path = path,
                Formatter = new XmlMessageFormatter(new Type[] { typeof(string) })
            };
            return mq.GetAllMessages().Where(t => t.Body.ToString().Split('|')[1] == destUser).ToArray();
        }
        public static void RemoveMessage(Message msg)
        {
            string path = @".\private$\mqDemo4";
            MessageQueue mq = new MessageQueue()
            {
                Path = path,
                Formatter = new XmlMessageFormatter(new Type[] { typeof(string) })
            };
            mq.ReceiveById(msg.Id);
        }
        public static void RemoveMessages(Message[] msgs)
        {
            string path = @".\private$\mqDemo4";
            MessageQueue mq = new MessageQueue()
            {
                Path = path,
                Formatter = new XmlMessageFormatter(new Type[] { typeof(string) })
            };
            foreach (var item in msgs)
            {
                mq.ReceiveById(item.Id);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/wanglui1990/article/details/80404718
4.5