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

1.项目-高性能TcpServer - 1.网络通信协议

https://blog.csdn.net/arno1988/article/details/82463225

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

https://blog.csdn.net/arno1988/article/details/82463968

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

https://blog.csdn.net/arno1988/article/details/82464812

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

https://blog.csdn.net/arno1988/article/details/82465924

5.项目-高性能TcpServer - 5.客户端管理

https://blog.csdn.net/arno1988/article/details/82466070

需要代码的可联系 QQ:505645074

扫描二维码关注公众号,回复: 3145716 查看本文章

处理原理:

每个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##

猜你喜欢

转载自blog.csdn.net/arno1988/article/details/82464812