zoukankan      html  css  js  c++  java
  • C# WebSocket解析(收发数据包、分片超长包处理)


    using
    System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; namespace LaiHuaRendSpeederServer { public static class WebSocketSeverHelper { /// <summary> /// 打包服务器握手数据 /// </summary> public static byte[] PackageHandShakeData(string handShakeText) { //string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, length); string key = string.Empty; Regex reg = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n"); Match m = reg.Match(handShakeText); if (m.Value != "") { key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim(); } byte[] secKeyBytes = SHA1.Create().ComputeHash( Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); string secKey = Convert.ToBase64String(secKeyBytes); var responseBuilder = new StringBuilder(); responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine); responseBuilder.Append("Upgrade: websocket" + Environment.NewLine); responseBuilder.Append("Connection: Upgrade" + Environment.NewLine); responseBuilder.Append("Sec-WebSocket-Accept: " + secKey + Environment.NewLine + Environment.NewLine); //responseBuilder.Append("Sec-WebSocket-Protocol: " + "chat, superchat" + Environment.NewLine + Environment.NewLine); return Encoding.UTF8.GetBytes(responseBuilder.ToString()); } /// <summary> /// 解析客户端发送来的数据 /// </summary> public static string DecodeClientData(byte[] recBytes, int length) { if (length < 2) { return string.Empty; } bool fin = (recBytes[0] & 0x80) == 0x80; //0x80 = 1000,0000 第1bit = 1表示最后一帧 if (!fin) { if (recBytes[1] == 0xff) { } else return string.Empty; } bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码 if (!mask_flag) { return string.Empty;// 不包含掩码的暂不处理 } int payload_len = recBytes[1] & 0x7F; // 数据长度 byte[] masks = new byte[4]; byte[] payload_data; if (payload_len == 126) { Array.Copy(recBytes, 4, masks, 0, 4); payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); payload_data = new byte[payload_len]; Array.Copy(recBytes, 8, payload_data, 0, payload_len); } else if (payload_len == 127) { Array.Copy(recBytes, 10, masks, 0, 4); byte[] uInt64Bytes = new byte[8]; for (int i = 0; i < 8; i++) { uInt64Bytes[i] = recBytes[9 - i]; } UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); payload_data = new byte[len]; for (UInt64 i = 0; i < len; i++) { payload_data[i] = recBytes[i + 14]; } } else { Array.Copy(recBytes, 2, masks, 0, 4); payload_data = new byte[payload_len]; Array.Copy(recBytes, 6, payload_data, 0, payload_len); } for (var i = 0; i < payload_len; i++) { payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); } //var uuu = new byte[payload_data.Length * 3 / 4]; //for (int i = 0; i < uuu.Length; i++) //{ // uuu[i] = payload_data[i]; //} //Console.WriteLine("UUUUUU:" + Encoding.UTF8.GetString(uuu)); return Encoding.UTF8.GetString(payload_data); } public static byte[] DecodeClientByteData(byte[] recBytes, int length) { if (length < 2) { return null; } bool fin = (recBytes[0] & 0x80) == 0x80; //0x80 = 1000,0000 第1bit = 1表示最后一帧 //if (!fin) //{ // if (recBytes[1] == 0xff) // { // if (recBytes[0] == 0x01) // { // recBytes[0] += 0x80; // } // else // return null; // } // else // return null; //} bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码 if (!mask_flag) { return null;// 不包含掩码的暂不处理 } int payload_len = recBytes[1] & 0x7F; // 数据长度 byte[] masks = new byte[4]; byte[] payload_data; if (payload_len == 126) { Array.Copy(recBytes, 4, masks, 0, 4); payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); payload_data = new byte[payload_len]; Array.Copy(recBytes, 8, payload_data, 0, payload_len); } else if (payload_len == 127) { Array.Copy(recBytes, 10, masks, 0, 4); byte[] uInt64Bytes = new byte[8]; for (int i = 0; i < 8; i++) { uInt64Bytes[i] = recBytes[9 - i]; } UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); payload_data = new byte[len]; for (UInt64 i = 0; i < len; i++) { payload_data[i] = recBytes[i + 14]; } } else { Array.Copy(recBytes, 2, masks, 0, 4); payload_data = new byte[payload_len]; Array.Copy(recBytes, 6, payload_data, 0, payload_len); } for (var i = 0; i < payload_data.Length; i++) { payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); } return payload_data; } /// <summary> /// 把客户端消息打包处理 /// </summary> public static byte[] EncodeServerData(string msg) { byte[] content = null; byte[] temp = Encoding.UTF8.GetBytes(msg); if (temp.Length < 126) { content = new byte[temp.Length + 2]; content[0] = 0x81; content[1] = (byte)temp.Length; Array.Copy(temp, 0, content, 2, temp.Length); } else if (temp.Length < 0xFFFF) { content = new byte[temp.Length + 4]; content[0] = 0x81; content[1] = 126; content[2] = (byte)(temp.Length & 0xFF); content[3] = (byte)(temp.Length >> 8 & 0xFF); Array.Copy(temp, 0, content, 4, temp.Length); } else { // 暂不处理超长内容 } return content; } } }
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    
    namespace LaiHuaRendSpeederServer
    {
        public static class WebSocketExt
        {
            public static int SendProtocol(this Socket s, Protocol p)
            {
                var msg = JsonConvert.SerializeObject(p);
                Console.WriteLine("SendProtocol : " + msg);
                return s.Send(WebSocketSeverHelper.EncodeServerData(msg));
            }
            public static int ReceiveProtocol(this Socket s, ref Protocol p)
            {
                byte[] buffer = new byte[502400];
                int reccount = 0;
                List<ArraySegment<byte>> segList = new List<ArraySegment<byte>>();
                if (s.Connected)
                {
                    reccount = s.Receive(buffer);
                    if(reccount == 0)
                    {
                        s.Shutdown(SocketShutdown.Send);
                        p = null;
                        return 0;
                    }
                }
                byte[] r = new byte[reccount];
                Array.Copy(buffer, r, reccount);
                buffer = null;
                string mgs = string.Empty;
                if ((r[0] & 0x80) == 0)
                {
                    segList.Add(new ArraySegment<byte>(r, 0, reccount));
                    byte[] r2 = new byte[8];
                    while ((r2[0] & 0x80) == 0)
                    {
                        r2 = new byte[502400];
                        int cout = s.Receive(r2);
                        segList.Add(new ArraySegment<byte>(r2, 0, cout));
                    }
                    byte[] all = null;
                    for (int i = 0; i < segList.Count; i++)
                    {
                        if (all == null)
                        {
                            all = WebSocketSeverHelper.DecodeClientByteData(segList[i].Array, segList[i].Count);
                        }
                        else
                        {
                            var pit = WebSocketSeverHelper.DecodeClientByteData(segList[i].Array, segList[i].Count);
                            all = all.Concat(pit).ToArray();
                        }
                    }
                    mgs = Encoding.UTF8.GetString(all);
                }
                else
                {
                    mgs = WebSocketSeverHelper.DecodeClientData(r, r.Length);
                }
    
                if (mgs.Length < 150)
                {
                    Console.WriteLine("ReceiveProtocol : " + mgs);
                }
                else
                {
                    Console.WriteLine("ReceiveProtocol : " + mgs.Substring(0, 150));
                }
                try
                {
                    var f = mgs.Substring(1, mgs.Length - 2);
                    var menbs = f.Split(new string[] { "\",\"" }, StringSplitOptions.RemoveEmptyEntries);
                    if (menbs.Length != 4)
                    {
                        p = null;
                        return reccount;
                    }
                    p = new Protocol();
                    foreach (var item in menbs)
                    {
                        var pare = item.Split(new string[] { "\":\"" }, StringSplitOptions.None);
                        if (pare.Length != 2)
                        {
                            p = null;
                            return reccount;
                        }
                        switch (pare[0].Replace("\"", ""))
                        {
                            case "Head":
                                p.Head = pare[1].Replace("\"", "");
                                break;
                            case "Func":
                                p.Func = pare[1].Replace("\"", "");
                                break;
                            case "Name":
                                p.Name = pare[1].Replace("\"", "");
                                break;
                            case "Data":
                                p.Data = pare[1].Replace("\"", "");
                                break;
                            default:
                                p = null;
                                return reccount;
                                break;
                        }
                    }
                    //p = JsonConvert.DeserializeObject<Protocol>(mgs);
                }
                catch (Exception ex)
                {
                    var errormsg = JsonConvert.SerializeObject(
                        new Protocol() { Func = FUNC.ERROR, Data = ex.ToString() });
                    if (s.Connected)
                    {
                        s.Send(WebSocketSeverHelper.EncodeServerData(errormsg));
                    }
                    Console.WriteLine("ERROR : " + errormsg);
                    s.Close();
                }
                return reccount;
            }
        }
    }
  • 相关阅读:
    微服务架构技术栈选型手册(万字长文)
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    MFC对话框中使用CHtmlEditCtrl
    ATL开发 ActiveX控件的 inf文件模板
    ActiveX: 如何用.inf和.ocx文件生成cab文件
    Xslt 1.0中使用Array
    如何分隔两个base64字符串?
    An attempt was made to load a program with an incorrect format
    JQuery 公网 CDN
  • 原文地址:https://www.cnblogs.com/gaobw/p/8087384.html
Copyright © 2011-2022 走看看