我是靠谱客的博主 单身金鱼,最近开发中收集的这篇文章主要介绍基于.Net TcpListener 实现 WebSocketServer 通讯,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

续接上文,上文已经实现了一个可用的IOCP 完成端口服务了。

本来是准备用IOCP实现服务的,但是,在实现过程中出现了Bug,短时间搞不定。

就换另外一种技术 TcpListener 来实现。

这篇文章就根据此服务,来实现一个WebSocketServer。

虽然实现的效果不是很强大,我相信,对很多人来讲,还是具有很大的借鉴意义的。

这就是这篇文章的意义。

websocket lib

新建项目如下:
在这里插入图片描述

主要是对websocket 协议的实现

整体协议大致如下:

在这里插入图片描述

实际过程中 客户端请求的是http的get请求,然后,服务端,根据Upgrade (升级)机制,来实现一个请求的升级和切换。

握手协议

客户端请求

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

服务端返回

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13

大概是这样子的。

握手完毕,就开始用Socket开始通讯。

websocket 握手协议

    //GET / HTTP/1.1
    //Host: localhost:9999
    //Connection: Upgrade
    //Pragma: no-cache
    //Cache-Control: no-cache
    //Upgrade: websocket
    //Origin: file://
    //Sec-WebSocket-Version: 13
    //User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36
    //Accept-Encoding: gzip, deflate, br
    //Accept-Language: zh-CN,zh;q=0.9,ja;q=0.8,nl;q=0.7
    //Cookie: _ga=GA1.1.601168430.1540570802
    //Sec-WebSocket-Key: TV0AyXfLhtkIDU2OBa7cmw==
    //Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

    /// <summary>
    /// 创建websocket所需要的头部握手协议
    /// </summary>
    public class WebSocketHeader
    {
        /// <summary>
        /// 协议头部信息
        /// </summary>
        private string Head = "GET {urladdress} HTTP/1.1";
        /// <summary>
        /// 头部请求信息
        /// </summary>
        private string HeadStr = string.Empty;
        /// <summary>
        /// 内置换行
        /// </summary>
        private string NewLine = "rn";
        /// <summary>
        /// 数值之间的分隔符
        /// </summary>
        private string splitStr = ": ";
        /// <summary>
        /// 魔数
        /// </summary>
        private const string MagicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        /// <summary>
        /// 所有可选的头部
        /// </summary>
        private Dictionary<string, string> Heads = new Dictionary<string, string>();
        /// <summary>
        /// 内置随机
        /// </summary>
        private static RandomNumberGenerator random = new RNGCryptoServiceProvider();
        /// <summary>
        /// websocketkey信息
        /// </summary>
        private string SecWebSocketKey { get; set; }
        /// <summary>
        /// 默认链接
        /// </summary>
        /// <param name="Host">localhost:9999</param>
        /// <param name=""></param>
        public WebSocketHeader(string url)
        {
            SecWebSocketKey = CreateBase64Key();
            var URL = ToUri(url);
            HeadStr = Head.Replace("{urladdress}", URL.AbsolutePath);
            var port = URL.Port;
            var schm = URL.Scheme;
            string Host = (port == 80 && schm == "ws") ||
                (port == 443 && schm == "wss") ? URL.DnsSafeHost : URL.Authority;
            string Origin = URL.OriginalString;
            if (!string.IsNullOrEmpty(Host)) { Add("Host", Host); }
            if (!string.IsNullOrEmpty(Origin)) { Add("Origin", Origin); }
            Add("Sec-WebSocket-Key", SecWebSocketKey);
            Add("Connection", "Upgrade");
            Add("Upgrade", "websocket");
            Add("Sec-WebSocket-Version", "13");
            Add("Sec-WebSocket-Extensions", "permessage-deflate; client_max_window_bits");
        }
        /// <summary>
        /// 默认链接
        /// </summary>
        /// <param name="Host">localhost:9999</param>
        /// <param name=""></param>
        public WebSocketHeader(Uri URL)
        {
            HeadStr = Head.Replace("{urladdress}", URL.AbsolutePath);
            SecWebSocketKey = CreateBase64Key();
            var port = URL.Port;
            var schm = URL.Scheme;
            string Host = (port == 80 && schm == "ws") ||
                (port == 443 && schm == "wss") ? URL.DnsSafeHost : URL.Authority;
            string Origin = URL.OriginalString;
            if (!string.IsNullOrEmpty(Host)) { Add("Host", Host); }
            if (!string.IsNullOrEmpty(Origin)) { Add("Origin", Origin); }
            Add("Sec-WebSocket-Key", SecWebSocketKey);
            Add("Connection", "Upgrade");
            Add("Upgrade", "websocket");
            Add("Sec-WebSocket-Version", "13");
            Add("Sec-WebSocket-Protocol", "chat, superchat");
        }
        /// <summary>
        /// 增加数据
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void Add(string name, string value)
        {
            if (Heads.ContainsKey(name))
            {
                Heads[name] = value;
            }
            else
            {
                Heads.Add(name, value);
            }
        }
        /// <summary>
        /// 获取需要发送的数据
        /// </summary>
        /// <returns></returns>
        public byte[] GetRequestByte()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(HeadStr + NewLine);
            foreach (var item in Heads)
            {
                sb.Append(item.Key + splitStr + item.Value + NewLine);
            }
            sb.Append(NewLine);
            string html = sb.ToString();
            return Encoding.UTF8.GetBytes(html);
        }
        /// <summary>
        /// 直接生成websocket所需要的key
        /// </summary>
        /// <returns></returns>
        public static string CreateBase64Key()
        {
            var src = new byte[16];
            random.GetBytes(src);
            return Convert.ToBase64String(src);
        }
        /// <summary>
        /// 验证签名是否正确
        /// </summary>
        /// <returns></returns>
        public bool CheckSecWebSocketKey(string key)
        {
            string temp = key;
            if (!string.IsNullOrEmpty(key))
            {
                if (key.IndexOf("Sec-WebSocket-Accept") > -1)
                {
                    string info = key;
                    string[] list = info.Split(new string[] { "rn" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var item in list.Reverse())
                    {
                        if (item.IndexOf("Sec-WebSocket-Accept") > -1)
                        {
                            key = item.Split(new string[] { splitStr }, StringSplitOptions.None)[1];
                            break;
                        }
                    }

                }
                var Akey = CreateResponseKey(SecWebSocketKey);
                if (key != Akey)
                {
                    return false;
                }
                if (temp.IndexOf("101") < 0)
                {
                    return false;
                }
                return true;

            }
            return false;
        }
        /// <summary>
        /// 与服务器进行验签
        /// </summary>
        /// <param name="base64Key"></param>
        /// <returns></returns>
        private static string CreateResponseKey(string base64Key)
        {
            var buff = new StringBuilder(base64Key, 64);
            buff.Append(MagicKey);
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            var src = sha1.ComputeHash(Encoding.ASCII.GetBytes(buff.ToString()));

            return Convert.ToBase64String(src);
        }
        /// <summary>
        /// 获取URL地址
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Uri ToUri(string value)
        {
            Uri ret;
            Uri.TryCreate(value, MaybeUri(value) ? UriKind.Absolute : UriKind.Relative, out ret);
            return ret;
        }
        /// <summary>
        /// 查看是否是一个URL地址
        /// </summary>
        private static bool MaybeUri(string value)
        {
            if (value == null)
                return false;

            if (value.Length == 0)
                return false;

            var idx = value.IndexOf(':');
            if (idx == -1)
                return false;

            if (idx >= 10)
                return false;

            var schm = value.Substring(0, idx);
            return IsPredefinedScheme(schm);
        }
        /// <summary>
        /// 对URL地址进行预处理
        /// </summary>
        private static bool IsPredefinedScheme(string value)
        {
            if (value == null || value.Length < 2)
                return false;

            var c = value[0];
            if (c == 'h')
                return value == "http" || value == "https";

            if (c == 'w')
                return value == "ws" || value == "wss";

            if (c == 'f')
                return value == "file" || value == "ftp";

            if (c == 'g')
                return value == "gopher";

            if (c == 'm')
                return value == "mailto";

            if (c == 'n')
            {
                c = value[1];
                return c == 'e'
                       ? value == "news" || value == "net.pipe" || value == "net.tcp"
                       : value == "nntp";
            }

            return false;
        }
    }

websocket 通讯协议的实现

主要的核心就是实现Websocket协议的实现

    /// <summary>
    /// webSocket协议
    /// </summary>
    public class WebSocketProtocol
    {
        /// <summary>
        /// WebSocket 握手 key 魔数
        /// </summary>
        private const string MagicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        /// <summary>
        /// 是否启动了掩码
        /// </summary>
        private const char charOne = '1';
        private const char charZero = '0';
        #region 协议之 握手
        /// <summary>
        /// 协议处理-http协议握手
        /// </summary>
        public static byte[] HandshakeMessage(string data)
        {
            string key = string.Empty;
            string info = data;
            //一步一步来
            string[] list = info.Split(new string[] { "rn" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in list.Reverse())
            {
                if (item.IndexOf("Sec-WebSocket-Key") > -1)
                {
                    key = item.Split(new string[] { ": " }, StringSplitOptions.None)[1];
                    break;
                }
            }
            //获取标准的key
            key = getResponseKey(key);
            //拼装返回的协议内容
            var responseBuilder = new StringBuilder();
            responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "rn");
            responseBuilder.Append("Upgrade: websocket" + "rn");
            responseBuilder.Append("Connection: Upgrade" + "rn");
            responseBuilder.Append("Sec-WebSocket-Accept: " + key + "rnrn");
            return Encoding.UTF8.GetBytes(responseBuilder.ToString());
        }
        /// <summary>
        /// 获取返回验证的key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string getResponseKey(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return string.Empty;
            }
            else
            {
                key += MagicKey;
                key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key.Trim())));
                return key;
            }
        }
        #endregion
        #region 协议包解析
        #region 解码
        /// <summary>
        /// 判断数据是否足够
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool DataEnough(long AllLength, MessageHeader header, byte[] data, ref long ReadLength)
        {
            if (data == null || data.Length < 3) { return false; }
            //判断数据是否足够
            Byte[] buffer = data;
            if (AllLength > (long)header.Payloadlen)
            {
                ReadLength = header.PayloadDataStartIndex + (long)header.Payloadlen;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 解码数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Message Decode(Byte[] data, MessageHeader header)
        {
            Message msg = new Message();
            msg.head = header;
            if (data == null || data.Length == 0)
            {
                msg.Data = string.Empty;
                return msg;
            }

            Byte[] payload = null;
            if (header != null)
            {
                //payload = new Byte[data.Length - header.PayloadDataStartIndex];
                if (header.Payloadlen > 0)
                {
                    payload = new Byte[(int)header.Payloadlen];
                }
                else
                {
                    payload = new Byte[data.Length - header.PayloadDataStartIndex];
                }
                Buffer.BlockCopy(data, header.PayloadDataStartIndex, payload, 0, payload.Length);
                if (header.MASK == charOne)
                {
                    for (int i = 0; i < payload.Length; i++)
                    {
                        payload[i] = (Byte)(payload[i] ^ header.Maskey[i % 4]);
                    }
                }
            }
            else
            {
                msg.Data = Encoding.UTF8.GetString(data);
                return msg;
            }
            if (header.Opcode == OperType.Text)
            {
                msg.Data = Encoding.UTF8.GetString(payload);
            }
            return msg;
        }
        /// <summary>
        /// 解码数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Message Decode(Byte[] data)
        {
            Byte[] buffer = new Byte[14];
            if (data.Length >= 14)
            {
                Buffer.BlockCopy(data, 0, buffer, 0, 14);
            }
            else
            {
                Buffer.BlockCopy(data, 0, buffer, 0, data.Length);
            }
            MessageHeader header = analyseHead(buffer);
            Message msg = new Message();
            msg.head = header;
            if (data == null || data.Length == 0)
            {
                msg.Data = string.Empty;
                return msg;
            }

            Byte[] payload = null;
            if (header != null)
            {
                //payload = new Byte[data.Length - header.PayloadDataStartIndex];
                if (header.Payloadlen > 0)
                {
                    payload = new Byte[(int)header.Payloadlen];
                }
                else
                {
                    payload = new Byte[data.Length - header.PayloadDataStartIndex];
                }
                Buffer.BlockCopy(data, header.PayloadDataStartIndex, payload, 0, payload.Length);
                if (header.MASK == charOne)
                {
                    for (int i = 0; i < payload.Length; i++)
                    {
                        payload[i] = (Byte)(payload[i] ^ header.Maskey[i % 4]);
                    }
                }
            }
            else
            {
                msg.Data = Encoding.UTF8.GetString(data);
                return msg;
            }
            if (header.Opcode == OperType.Text)
            {
                msg.Data = Encoding.UTF8.GetString(payload);
            }
            return msg;
        }
        /// <summary>
        /// 判断此数据是否是合格的头部信息
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool IsHead(byte[] data, ref MessageHeader header)
        {
            if (data != null && data.Length > 2)
            {
                var head = analyseHead(data);
                header = head;
                if (head != null)
                {
                    if (head.RSV1 == '0' && head.RSV2 == '0' && head.RSV3 == '0')
                    {
                        if (head.Opcode == OperType.Binary || head.Opcode == OperType.Close || head.Opcode == OperType.Ping || head.Opcode == OperType.Pong || head.Opcode == OperType.Row || head.Opcode == OperType.Text)
                        {
                            if (head.MASK == '0')
                            {

                                int lenSize = (int)head.Payloadlen;
                                if (lenSize > 125)
                                {
                                    if (lenSize > 0xFFFF)
                                    {
                                        lenSize = 127;
                                    }
                                    else
                                    {
                                        lenSize = 126;
                                    }
                                }
                                if (lenSize == head.Len)
                                {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 解析数据的头部信息
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private static MessageHeader analyseHead(Byte[] buffer)
        {
            MessageHeader header = new MessageHeader();
            header.FIN = (buffer[0] & 0x80) == 0x80 ? charOne : charZero;
            header.RSV1 = (buffer[0] & 0x40) == 0x40 ? charOne : charZero;
            header.RSV2 = (buffer[0] & 0x20) == 0x20 ? charOne : charZero;
            header.RSV3 = (buffer[0] & 0x10) == 0x10 ? charOne : charZero;
            // 判断是否为结束针
            header.IsEof = (buffer[0] >> 7) > 0;
            if ((buffer[0] & 0xA) == 0xA)
                header.Opcode = OperType.Pong;
            else if ((buffer[0] & 0x9) == 0x9)
                header.Opcode = OperType.Ping;
            else if ((buffer[0] & 0x8) == 0x8)
                header.Opcode = OperType.Close;
            else if ((buffer[0] & 0x2) == 0x2)
                header.Opcode = OperType.Binary;
            else if ((buffer[0] & 0x1) == 0x1)
                header.Opcode = OperType.Text;
            else if ((buffer[0] & 0x0) == 0x0)
                header.Opcode = OperType.Row;

            header.MASK = (buffer[1] & 0x80) == 0x80 ? charOne : charZero;
            Int32 len = buffer[1] & 0x7F;
            header.Len = len;
            if (len == 126)
            {
                header.Payloadlen = (UInt64)(buffer[2] << 8 | buffer[3]);
                if (header.MASK == charOne)
                {
                    header.Maskey = new Byte[4];
                    Buffer.BlockCopy(buffer, 4, header.Maskey, 0, 4);
                    header.PayloadDataStartIndex = 8;
                }
                else
                    header.PayloadDataStartIndex = 4;
            }
            else if (len == 127)
            {
                Byte[] byteLen = new Byte[8];
                Buffer.BlockCopy(buffer, 2, byteLen, 0, 8);
                Array.Reverse(byteLen);
                header.Payloadlen = BitConverter.ToUInt64(byteLen, 0);
                if (header.MASK == charOne)
                {
                    header.Maskey = new Byte[4];
                    Buffer.BlockCopy(buffer, 10, header.Maskey, 0, 4);
                    header.PayloadDataStartIndex = 14;
                }
                else
                    header.PayloadDataStartIndex = 10;
            }
            else
            {
                header.Payloadlen = (ulong)len;
                if (header.MASK == charOne)
                {
                    header.Maskey = new Byte[4];
                    Buffer.BlockCopy(buffer, 2, header.Maskey, 0, 4);
                    header.PayloadDataStartIndex = 6;
                }
                else
                    header.PayloadDataStartIndex = 2;
            }
            return header;
        }
        #endregion
        #region 编码
        /// <summary>
        /// 把客户端消息打包处理
        /// </summary>
        /// <returns>The data.</returns>
        /// <param name="message">Message.</param>
        public static byte[] PackageServerData(byte[] message, bool IsMask = true)
        {
            byte[] bytData = message;
            byte[] MaskingKey = null;
            if (IsMask)
            {
                MaskingKey = createMaskingKey();
            }
            UInt64 length = (UInt64)bytData.Length;
            byte len = (byte)length, lenSize = 0;
            if (length > 125)
            {
                if (length > 0xFFFF)
                {
                    len = 127;
                    lenSize = 8;
                }
                else
                {
                    len = 126;
                    lenSize = 2;
                }
            }

            bool Mask = (MaskingKey != null);
            UInt64 offset = (UInt64)(2 + lenSize);

            byte[] bytBuffer = new byte[2 + (UInt64)(Mask ? 4 : 0) + length + (UInt64)lenSize];
            bytBuffer[0] = (byte)(0x80 | (byte)1);
            bytBuffer[1] = (byte)((Mask ? 0x80 : 0) | len);

            if (lenSize == 2)
            {
                bytBuffer[2] = (byte)(length >> 8 & 0xFF);
                bytBuffer[3] = (byte)(length & 0xFF);
            }
            else if (lenSize == 4)
            {
                bytBuffer[2] = (byte)(length >> 56 & 0xFF);
                bytBuffer[3] = (byte)(length >> 48 & 0xFF);
                bytBuffer[4] = (byte)(length >> 40 & 0xFF);
                bytBuffer[5] = (byte)(length >> 32 & 0xFF);
                bytBuffer[6] = (byte)(length >> 24 & 0xFF);
                bytBuffer[7] = (byte)(length >> 16 & 0xFF);
                bytBuffer[8] = (byte)(length >> 8 & 0xFF);
                bytBuffer[9] = (byte)(length & 0xFF);
            }

            if (Mask)
            {
                for (UInt64 i = 0; i < 4; i++)
                {
                    bytBuffer[offset + i] = MaskingKey[i];
                }
                offset += 4;
            }

            for (UInt64 i = 0; i < length; i++)
            {
                if (Mask) bytData[i] ^= MaskingKey[i % 4];
                bytBuffer[offset + i] = bytData[i];
            }

            return bytBuffer;
        }
        /// <summary>
        /// 打包消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="IsMask">是否启用虚码,服务器给客户端 不可以用,客户端给服务器,必须用</param>
        /// <returns></returns>
        public static byte[] PackageServerData(string message, bool IsMask = true)
        {
            byte[] bytData = Encoding.UTF8.GetBytes(message);
            byte[] MaskingKey = null;
            if (IsMask)
            {
                MaskingKey = createMaskingKey();
            }
            UInt64 length = (UInt64)bytData.Length;
            byte len = (byte)length, lenSize = 0;
            if (length > 125)
            {
                if (length > 0xFFFF)
                {
                    len = 127;
                    lenSize = 8;
                }
                else
                {
                    len = 126;
                    lenSize = 2;
                }
            }

            bool Mask = (MaskingKey != null);
            UInt64 offset = (UInt64)(2 + lenSize);

            byte[] bytBuffer = new byte[2 + (UInt64)(Mask ? 4 : 0) + length + (UInt64)lenSize];
            bytBuffer[0] = (byte)(0x80 | (byte)1);
            bytBuffer[1] = (byte)((Mask ? 0x80 : 0) | len);

            if (lenSize == 2)
            {
                bytBuffer[2] = (byte)(length >> 8 & 0xFF);
                bytBuffer[3] = (byte)(length & 0xFF);
            }
            else if (lenSize == 4)
            {
                bytBuffer[2] = (byte)(length >> 56 & 0xFF);
                bytBuffer[3] = (byte)(length >> 48 & 0xFF);
                bytBuffer[4] = (byte)(length >> 40 & 0xFF);
                bytBuffer[5] = (byte)(length >> 32 & 0xFF);
                bytBuffer[6] = (byte)(length >> 24 & 0xFF);
                bytBuffer[7] = (byte)(length >> 16 & 0xFF);
                bytBuffer[8] = (byte)(length >> 8 & 0xFF);
                bytBuffer[9] = (byte)(length & 0xFF);
            }

            if (Mask)
            {
                for (UInt64 i = 0; i < 4; i++)
                {
                    bytBuffer[offset + i] = MaskingKey[i];
                }
                offset += 4;
            }

            for (UInt64 i = 0; i < length; i++)
            {
                if (Mask) bytData[i] ^= MaskingKey[i % 4];
                bytBuffer[offset + i] = bytData[i];
            }

            return bytBuffer;
        }
        /// <summary>
        /// 创建一个 Mask 掩码
        /// </summary>
        /// <returns></returns>
        private static byte[] createMaskingKey()
        {
            var key = new byte[4];
            new RNGCryptoServiceProvider().GetBytes(key);
            return key;
        }
        #endregion
        #endregion
    }

实现WebsocketServer

是基于 TcpListener 实现的, IOCP 的例子,暂时没了。估计也没人需要。

    /// <summary>
    /// WebSocketServer
    /// </summary>
    public class WebSocketServer
    {
        /// <summary>
        /// 核心监听方法
        /// </summary>
        TcpListener listener;
        /// <summary>
        /// 服务端监听的端口  作为服务端口
        /// </summary>
        public int ListenPort;
        /// <summary>
        /// 监听的端口
        /// </summary>
        /// <param name="port"></param>
        public WebSocketServer(int port)
        {
            this.ListenPort = port;
        }
        /// <summary>
        /// websocket 事件
        /// </summary>
        /// <param name="UserToken"></param>
        public delegate void WebSocketHandler(Socket socket, string data);
        /// <summary>
        /// 新用户的事件
        /// </summary>
        public event WebSocketHandler OnOpen;
        /// <summary>
        /// 新用户的事件
        /// </summary>
        public event WebSocketHandler OnClose;
        /// <summary>
        /// 新用户的事件
        /// </summary>
        public event WebSocketHandler OnMessage;
        /// <summary>
        /// 开始监听
        /// </summary>
        /// <returns></returns>
        public WebSocketServer Listen()
        {
            listener = new TcpListener(IPAddress.Any, this.ListenPort);
            listener.Start();
            ServerStart();
            Task.Run(() =>
            {
                while (true)
                {
                    TcpClient s = listener.AcceptTcpClient();
                    //来一个新的链接
                    ThreadPool.QueueUserWorkItem(r => { Accept(s); });
                }
            });
            return this;
        }
        /// <summary>
        /// 一个新的连接
        /// </summary>
        /// <param name="s"></param>
        public void Accept(TcpClient s)
        {
            BinaryReader rs = new BinaryReader(s.GetStream());
            var ReceiveBuffer = new byte[1024];
            List<byte> ReceiveList = new List<byte>();
            UserToken userToken = new UserToken();
            userToken.ConnectSocket = s.Client;
            userToken.ConnectTime = DateTime.Now;
            userToken.RemoteAddress = s.Client.RemoteEndPoint;
            userToken.IPAddress = ((IPEndPoint)(userToken.RemoteAddress)).Address;

            try
            {
                newAcceptHandler(userToken);
                while (s.Connected)
                {
                    int length = 0;
                    try
                    {
                        length = rs.Read(ReceiveBuffer, 0, ReceiveBuffer.Length);
                        //如果没有读完,就一直读
                        for (int i = 0; i < length; i++)
                        {
                            ReceiveList.Add(ReceiveBuffer[i]);
                        }
                        if (s.Client.Available == 0)
                        {
                            var data = ReceiveList.ToArray();
                            //接收完毕
                            Task.Run(() => ReceiveHandler(userToken, data));
                            ReceiveList.Clear();
                        }
                    }
                    catch (Exception)
                    {
                        break;
                    }
                    if (length == 0)
                    {
                        break;
                    }
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                s.Close();//客户端连接关闭
                newQuitHandler(userToken);
            }
        }
        /// <summary>
        /// 接收信息的处理
        /// </summary>
        /// <param name="UserToken"></param>
        public void ReceiveHandler(UserToken userToken, byte[] Receivedata)
        {
            //说明第一次链接,先进行握手
            if (!userToken.temp.ContainsKey("WebSocket"))
            {
                string info = Encoding.UTF8.GetString(Receivedata);
                if (info.IndexOf("websocket") > -1)
                {
                    var send = userToken.ConnectSocket.Send(WebSocketProtocol.HandshakeMessage(info));
                    if (send > 0)
                    {
                        userToken.temp.Add("WebSocket", true);
                    }
                }
            }
            else
            {
                var data = WebSocketProtocol.Decode(Receivedata);
                if (data != null)
                {
                    if (data.head.Opcode == OperType.Close)
                    {
                        userToken.ConnectSocket.Close();
                    }
                    else
                    {
                        if (OnMessage != null)
                        {
                            OnMessage(userToken.ConnectSocket, data.Data);
                        }
                        else
                        {
                            //接管数据处理
                            Console.WriteLine("收到数据");
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 新的链接
        /// </summary>
        public void newAcceptHandler(UserToken userToken)
        {
            if (OnOpen != null)
            {
                OnOpen(userToken.ConnectSocket, null);
            }
            Console.WriteLine("一个新的用户:" + userToken.RemoteAddress.ToString());
        }
        /// <summary>
        /// 服务开始
        /// </summary>
        public void ServerStart()
        {
            Console.WriteLine("服务开启:local:" + this.ListenPort);
        }
        /// <summary>
        /// 用户退出
        /// </summary>
        public void newQuitHandler(UserToken userToken)
        {
            if (OnClose != null)
            {
                OnClose(userToken.ConnectSocket, null);
            }
            Console.WriteLine("用户退出:" + userToken.RemoteAddress.ToString());
        }
        /// <summary>
        /// 对客户发送数据
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public int SendMessage(Socket socket, string data)
        {
            int length = -1;
            try
            {
                var bytes = WebSocketProtocol.PackageServerData(Encoding.UTF8.GetBytes(data), false);
                if (socket != null && socket.Connected)
                {
                    length = socket.Send(bytes);
                }
            }
            catch (Exception ex)
            { }
            return length;
        }
    }

服务端测试验证

    class Program
    {
        static WebSocketServer smartWebSocketServer;
        static void Main(string[] args)
        {
            Console.Title = "WebSocket Server Demo 蓝总创精英团队!";
            smartWebSocketServer = new WebSocketServer(5000);
            smartWebSocketServer.OnMessage += WebSocketServer_OnMessage;
            smartWebSocketServer.Listen();
            Console.WriteLine("开始监听!");
            Console.ReadLine(); 
        }

        private static void WebSocketServer_OnMessage(System.Net.Sockets.Socket socket, string data)
        {
            Console.WriteLine("收到客户端的数据:" + data);
            smartWebSocketServer.SendMessage(socket, data);
        }
    }

客户端测试验证

    class Program
    {
        static async Task Main(string[] args)
        {
            Console.Title = "WebSocket Client Demo 蓝总创精英团队!";
            var webSocket = await CreateAsync("ws://localhost:5000");
            if (webSocket != null)
            {
                Console.WriteLine("服务开始执行!");
                _ = Task.Run(async () =>
                {
                    var buffer = ArrayPool<byte>.Shared.Rent(1024);
                    try
                    {
                        while (webSocket.State == WebSocketState.Open)
                        {
                            var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
                            if (result.MessageType == WebSocketMessageType.Close)
                            {
                                throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, result.CloseStatusDescription);
                            }
                            var text = Encoding.UTF8.GetString(buffer.AsSpan(0, result.Count));
                            Console.WriteLine("来自服务端:" + text);
                        }
                    }
                    finally
                    {
                        ArrayPool<byte>.Shared.Return(buffer);
                    }
                });
                Console.WriteLine("开始输入:");
                Thread.Sleep(1000);
                var text = string.Empty;
                while (text != "exit")
                {
                    text = Console.ReadLine();
                    var sendStr = Encoding.UTF8.GetBytes(text);
                    if (webSocket.State != WebSocketState.Open)
                    {
                        Console.WriteLine("服务端自己关闭了连接!");
                    }
                    await webSocket.SendAsync(sendStr, WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
            else
            {
                Console.WriteLine("服务连接失败!");
            }
            Console.WriteLine("服务执行完毕!");
            Console.ReadLine();
        }
        /// <summary>
        /// 创建客户端实例
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task<ClientWebSocket> CreateAsync(string ServerUri)
        {
            var webSocket = new ClientWebSocket();
            webSocket.Options.RemoteCertificateValidationCallback = delegate { return true; };

            await webSocket.ConnectAsync(new Uri(ServerUri), CancellationToken.None);
            if (webSocket.State == WebSocketState.Open)
            {
                return webSocket;
            }
            return null;
        }
    }

结果展示

先开启服务端,然后,在开启客户端
在这里插入图片描述

服务端已开启,然后开启客户端

在这里插入图片描述

这个时候已经看到服务端收到连接了。

加粗样式
结果还是很顺畅的。

总结

很多时候,深入底层甚至协议是有必要的,要不然,自己都不知道自己还知道点什么,毕竟大家都知道了。所以,知道一些别人不知道的,意义还是蛮大的。

代码地址

https://github.com/kesshei/CustomWebSocketServerDemo.git

https://gitee.com/kesshei/CustomWebSocketServerDemo.git

最后

以上就是单身金鱼为你收集整理的基于.Net TcpListener 实现 WebSocketServer 通讯的全部内容,希望文章能够帮你解决基于.Net TcpListener 实现 WebSocketServer 通讯所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部