高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包)

Posted chen1880

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包)相关的知识,希望对你有一定的参考价值。

高性能TcpServer(C#) - 1.网络通信协议

高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

高性能TcpServer(C#) - 3.命令通道(处理:掉包,粘包,垃圾包)

高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)

高性能TcpServer(C#) - 5.客户端管理

高性能TcpServer(C#) - 6.代码下载

 

处理原理

每个client创建各自的byte[]数组,通过遍历每个字节的数据

1.判断包长,确定掉包;

2.判断解析完后byte数组是否还有未解析的数据,确定粘包;

3.判断包头,确定垃圾包;

 

缓存数据类

 /// <summary>

    /// 缓存数据类

    /// </summary>

    public class CByteBuffer

    {

        // 默认1k

        int m_iBufferSize = 1024 * 1;

 

        // 数据解析

        byte[] m_abyBuf;

        int m_iPosition = 0;

        int m_iRecvLength = 0;

        bool bWaitRecvRemain;// 数据未接收完等待接收

        object m_lock = new object(); // 内部同步锁

 

        public int Position

        {

            get { return m_iPosition; }

            set { m_iPosition = value; }

        }

 

        public int RecvLength

        {

            get { return m_iRecvLength; }

            set { m_iRecvLength = value; }

        }

 

        public bool WaitRecvRemain

        {

            get { return bWaitRecvRemain; }

            set { bWaitRecvRemain = value; }

        }

 

        public CByteBuffer(int buffSize)

        {

            m_iBufferSize = buffSize;

            m_abyBuf = new byte[m_iBufferSize];

        }

 

        public int GetPosition()

        {

            return m_iPosition;

        }

 

        public int GetRecvLength()

        {

            return m_iRecvLength;

        }

 

        public void Put(SocketAsyncEventArgs e)

        {

            int iLength = e.BytesTransferred;

            if (m_iRecvLength + iLength >= m_iBufferSize)

            {

                Clear();

                return;

            }

 

            lock (m_lock)

            {

                Array.Copy(e.Buffer, e.Offset, m_abyBuf, m_iRecvLength, iLength);

                m_iRecvLength += iLength;

            }

        }

 

        public byte GetByte()

        {

            bWaitRecvRemain = false;

 

            if (m_iPosition >= m_iRecvLength)

            {

                bWaitRecvRemain = true;

                return 0;

            }

 

            byte byRet;

            lock (m_lock)

            {

                byRet = m_abyBuf[m_iPosition];

            }

            m_iPosition++;

 

            return byRet;

        }

 

        public byte[] GetByteArray(int Length)

        {

            bWaitRecvRemain = false;

 

            if (m_iPosition + Length > m_iRecvLength)

            {

                bWaitRecvRemain = true;

                return null;

            }

 

            byte[] ret = new byte[Length];

 

            lock (m_lock)

            {

                Array.Copy(m_abyBuf, m_iPosition, ret, 0, Length);

 

                m_iPosition += Length;

            }

 

            return ret;

        }

 

        public bool HasRemaining()

        {

            return m_iPosition < m_iRecvLength;

        }

 

        public int Remaining()

        {

            return m_iRecvLength - m_iPosition;

        }

 

        public void Clear()

        {

            m_iPosition = 0;

            m_iRecvLength = 0;

            bWaitRecvRemain = false;

        }

 

        ~CByteBuffer()

        {

            m_abyBuf = null;

            Dispose(false);

        }

 

        protected virtual void Dispose(bool disposing)

        {

            if (disposing)

            {

                GC.SuppressFinalize(this);

            }

        }

 

        public void Dispose()

        {

            Dispose(true);

        }

    }

协议解析类

        public void Process(CByteBuffer bBuffer, CProtocolAnalysis analysis, string sn)

        {

            analysis.BagStatus = CProtocolAnalysis.EBagStatus.BagNone;

            analysis.WhetherToSend = false;

 

            int iPosition = bBuffer.Position;

            byte head1 = 0; byte head2 = 0; byte head3 = 0; byte head4 = 0; byte head5 = 0; byte head6 = 0; bool headok = false;

 

            if (!bBuffer.HasRemaining()) return;

 

            while (bBuffer.HasRemaining())

            {

                head1 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                if (HEAD1 == head1)

                {

                    iPosition = bBuffer.Position - 1;

                    head2 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                    head3 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                    head4 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                    head5 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                    head6 = bBuffer.GetByte(); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                    if (HEAD2 == head2 && HEAD3 == head3 && HEAD4 == head4 && HEAD5 == head5 && HEAD6 == head6)

                    {

                        headok = true;

                        break;

                    }

                    else

                    {

                        CLogHelp.AppendLog("Error,Unable to parse the data2:Position=" + iPosition.ToString() + ",Index=" + (bBuffer.GetPosition()).ToString() + ",Head2=" + head2.ToString());

                    }

                }

                else

                {

                    CLogHelp.AppendLog("Error,Unable to parse the data1:Position=" + iPosition.ToString() + ",Index=" + (bBuffer.GetPosition()).ToString() + ",Head1=" + head1.ToString());

                }

            }

 

            if (!bBuffer.HasRemaining())

            {

                if (headok)

                {

                    if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

                }

                return;

            }

 

            byte[] arrlen = bBuffer.GetByteArray(4); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

            int len = CCommonFunc.String2Int(CCommonFunc.ByteToString(arrlen)); if (-1 == len) return;

            byte[] source = bBuffer.GetByteArray(len); if (!analysis.IsRemainData(iPosition, bBuffer, analysis)) return;

 

            if (!bBuffer.HasRemaining())

            {

                bBuffer.Clear();

            }

            else

            {

                analysis.BagStatus = CProtocolAnalysis.EBagStatus.BagStick;

            }

 

            // #WaterMeter-001#01##

            string data = CCommonFunc.ByteToString(source);

            if (null == data || 0 == data.Length || data.Length - 1 != data.LastIndexOf(SPLIT1))

            {

                return;

            }

            data = data.Substring(1, data.Length - 2);

            string[] item = data.Split(SPLIT1);

            if (null == item || 4 != item.Length)

            {

                return;

            }

            string uid = item[0];

            string taskid = item[1];

            int cmd = CCommonFunc.String2Int(item[2]);

            string content = item[3];

            Program.AddMessage("R: [" + sn + "] cmd=" + cmd.ToString() + " data=" + data);

 

            analysis.Cmd = cmd;

            analysis.Uid = uid;

            analysis.TaskId = taskid;

 

            if (cmd == 1 || cmd == 2 || cmd == 3 || cmd == 4 || cmd == 5 || cmd == 6 || cmd == 7)

            {

                analysis.WhetherToSend = true;

            }

 

            string softtype = "";  

 

            try

            {

                switch (cmd)

                {

                    case 1:

                        analysis.Msg = "ok";

                        break;

                    case 2:

                        analysis.Msg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                        break;

                    case 3:

                        // HTEMP=0263#WaterMeter-001#1520557004#03#buildid=44@edmid=37@meterid=1228@senddate=2018-02-05 17:36:22@[{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}+{132,0.0000}]#

                        analysis.Msg = "ok";

                        break;

                    case 4:

                        {

                            // 获取版本信息

                            softtype = content.Split(SPLIT2)[1];

                            StorageFile(softtype, System.Windows.Forms.Application.StartupPath + "\\\\test.zip");

                            analysis.Msg = "2";// version

                        }

                        break;

                    case 5:

                        // 获取包数

                        {

                            softtype = content.Split(SPLIT2)[1];

                            if (!dicSoft.ContainsKey(softtype))

                            {

                                StorageFile(softtype, System.Windows.Forms.Application.StartupPath + "\\\\test.zip");

                            }

                            // 获取包数

                            int count = 0;

                            FileCut entity = null;

                            dicSoft.TryGetValue(softtype, out entity);

                            if (null != entity) count = entity.Count;

                            analysis.Msg = count.ToString();

                        }

                        break;

                    case 6:

                        // 执行更新动作

                        {

                            string[] items = content.Split(SPLIT2);

                            softtype = items[1];

                            int downindex = CCommonFunc.String2Int(items[2]);

                            if (!dicSoft.ContainsKey(softtype))

                            {

                                analysis.Msg = "error@" + softtype + " 未找到更新文件,请先获取包数";

                            }

                            else

                            {

                                FileCut entity = null;

                                dicSoft.TryGetValue(softtype, out entity);

                                if (null != entity)

                                {

                                    string filedata = "";

                                    entity.Data.TryGetValue(downindex, out filedata);

                                    if (string.IsNullOrEmpty(filedata))

                                        analysis.Msg = "error@" + softtype + " 第" + downindex + "包的数据为空";

                                    else

                                        analysis.Msg = filedata;

                                }

                            }

                        }

                        break;

                    case 7:

                        // 更新版本信息(update sql)

                        analysis.Msg = "ok";

                        break;

                }

            }

            catch (Exception ex)

            {

                analysis.Msg = "error@" + ex.Message;

            }

            Program.AddMessage("S: [" + sn + "] cmd=" + cmd.ToString() + " data=" + analysis.Msg);

        }

测试效果

正常包

HTEMP=0026#Meter-001#1533022506#01##

 

 

掉包(分两包发送)

HTEMP=0026#

Meter-001#1533022506#01##

 

 

粘包(两包一起发送)

HTEMP=0026#Meter-001#1533022506#01##HTEMP=0026#Meter-001#1533022506#01##

 

 

以上是关于高性能TcpServer - 3.命令通道(处理:掉包,粘包,垃圾包)的主要内容,如果未能解决你的问题,请参考以下文章

高性能TcpServer - 4.文件通道(处理:文件分包,支持断点续传)

loadrunner11+12 app性能测试

CocosCreator游戏性能优化(3):GPU优化之降低计算分辨率

React Native 中 ScrollView 性能探究

性能测试的分类以及性能测试的指标

Spark性能调优篇七之JVM相关参数调整