DotNetty 使用ByteToMessageDecoder 国家部标808协议封装

DotNetty 开源地址 https://github.com/Azure/DotNetty

1.国家部标808协议格式

808协议.jpg

标识位
采用 0x7e 表示,若校验码、消息头以及消息体中出现 0x7e,则要进行转义处理,转义
规则定义如下:
0x7e <————> 0x7d 后紧跟一个 0x02;
0x7d <————> 0x7d 后紧跟一个 0x01。
转义处理过程如下:
发送消息时:消息封装——>计算并填充校验码——>转义;
接收消息时:转义还原——>验证校验码——>解析消息。
示例:
发送一包内容为 0x30 0x7e 0x08 0x7d 0x55 的数据包,则经过封装如下:0x7e 0x30 7d 0x02 0x08 0x7d0x01 0x55 0x7

2.建立一个控制台程序

  添加NuGet包

 System.Text.Encoding.CodePages

  Microsoft.Extensions.Configuration.CommandLine

  Microsoft.Extensions.Configuration.EnvironmentVariables

  Microsoft.Extensions.Configuration.Json

  Microsoft.Extensions.Hosting

  Microsoft.Extensions.Logging.Console

3.dotnetty 通道配置,使用默认的DelimiterBasedFrameDecoder 看看是否能够实现分包

  bootstrap.Option(ChannelOption.SoBacklog, 100).Handler(new LoggingHandler("SRV-LSTN"))
                    .ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        pipeline.AddLast(new LoggingHandler("SRV-CONN"));
                        pipeline.AddLast("framing-dec", new DelimiterBasedFrameDecoder(1024, false, LineDelimiter()));
                        pipeline.AddLast("ServerClientHandler", new DBServerClientHandler());
                    }));
   public static IByteBuffer[] LineDelimiter()
        {
            return new[]
            {
                Unpooled.WrappedBuffer(new[] { (byte)0x7e, (byte)0x7e }),
                Unpooled.WrappedBuffer(new[] { (byte)0x7e }),
            };
        }

用网络调试工具 发送数据 7E 81 00 00 03 01 82 40 55 60 49 00 00 00 01 04 38 7E ,发现服务器收到数据后,分包数据错误了(一包数据编程2包数据了,数据格式也不对),

更改下分隔符代码,也出现一样的结果

 public static IByteBuffer[] LineDelimiter()
        {
            return new[]
            {
                Unpooled.WrappedBuffer(new[] { (byte)0x7e }),
                Unpooled.WrappedBuffer(new[] { (byte)0x7e }),
            };
        }
   public static IByteBuffer[] LineDelimiter()
        {
            return new[]
            {
                Unpooled.WrappedBuffer(new[] { (byte)0x7e}),
            };
        }

网络调试工具.jpg接收数据.jpg

4.使用ByteToMessageDecoder,代码如下

/// <summary>
    ///粘包处理 数据包 头和尾 标志 都包含分割 字符串 
    /// </summary>
    public class BeiDouFrameDecoder : ByteToMessageDecoder
    {
        private int frameFlag = 0x7e;
        private int manFrameLength;
        private int minFrameLength;
        private int delimiters = 2;
        private IByteBuffer frameDelimiter;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="frameFlag">数据包 标志</param>
        /// <param name="maxFrameLength">数据包最大长度</param>
        /// <param name="minFrameLength">数据包最小长度</param>
        public BeiDouFrameDecoder(byte frameFlag, int maxFrameLength, int minFrameLength)
        {
            this.frameFlag = frameFlag;
            this.manFrameLength = maxFrameLength;
            this.minFrameLength = minFrameLength;
            frameDelimiter = Unpooled.WrappedBuffer(new[] { frameFlag });
        }

        protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output)
        {
            if (input.ReadableBytes <= minFrameLength)//还不够 最小帧的 数据
                return;

            int readLen = -1;
            //标记
            int OriginalReadIndex = input.ReaderIndex;
            input.MarkReaderIndex();
            if (frameFlag == input.GetByte(OriginalReadIndex))//找到头  第一个字节是头  不改变 ReaderIndex
            {
                input.SetReaderIndex(OriginalReadIndex + 1);
                readLen = IndexOfEnd(input);
                input.ResetReaderIndex();
                if (readLen != -1)//没有找到尾
                {
                    readLen += delimiters;
                    if (readLen > manFrameLength || readLen < minFrameLength)
                    {
                        input.SkipBytes(readLen);
                    }
                    else
                    {
                        IByteBuffer frame = input.ReadSlice(readLen);
                        frame.Retain();
                        output.Add(frame);
                    }
                }
            }
            else
            {
                //找头
                int readIndex = -1;
                int seekReaderIndex = input.ReaderIndex + 1;
                while (seekReaderIndex < input.WriterIndex)
                {
                    if (frameFlag == input.GetByte(seekReaderIndex))//找到头部
                    {
                        readIndex = seekReaderIndex;
                        break;
                    }
                    seekReaderIndex++;
                }

                if (readIndex != -1)//找到头
                {
                    if ((input.ReadableBytes - readIndex) < minFrameLength)//可以读取的 数据长度小于最小帧长度,说明还不够一包数据,等下一次再读取
                    {
                        input.ResetReaderIndex();//本次跳过 还原ReaderIndex
                        return;
                    }

                    input.SetReaderIndex(readIndex + 1);
                    readLen = IndexOfEnd(input);
                    if (readLen == -1)//没有找打 尾
                    {
                        input.SkipBytes(input.ReadableBytes);//本次跳过 后面的所有字节
                    }
                    else if (readLen > manFrameLength || readLen < minFrameLength)//找到帧 但是长度 小于 最小长度  是错误的帧 SkipBytes
                    {
                        input.SetReaderIndex(readIndex);
                        input.SkipBytes(readLen + delimiters);
                    }
                    else
                    {
                        input.SetReaderIndex(readIndex);
                        IByteBuffer frame = input.ReadSlice(readLen + delimiters);
                        frame.Retain();
                        output.Add(frame);
                    }
                }
            }
        }

        private int IndexOfEnd(IByteBuffer haystack)
        {
            for (int i = haystack.ReaderIndex; i < haystack.WriterIndex; i++)
            {
                if (haystack.GetByte(i) != frameFlag)
                {
                    continue;
                }
                else
                {
                    if (i == haystack.WriterIndex)
                    {
                        return -1;
                    }
                }
                //Found the needle from the haystack!  找到
                return i - haystack.ReaderIndex;
            }
            return -1;
        }


        //private static int IndexOf(IByteBuffer haystack, IByteBuffer needle)
        //{
        //    for (int i = haystack.ReaderIndex; i < haystack.WriterIndex; i++)
        //    {
        //        int haystackIndex = i;
        //        int needleIndex;
        //        for (needleIndex = 0; needleIndex < needle.Capacity; needleIndex++)
        //        {
        //            if (haystack.GetByte(haystackIndex) != needle.GetByte(needleIndex))
        //            {
        //                break;
        //            }
        //            else
        //            {
        //                haystackIndex++;
        //                if (haystackIndex == haystack.WriterIndex && needleIndex != needle.Capacity - 1)
        //                {
        //                    return -1;
        //                }
        //            }
        //        }

        //        if (needleIndex == needle.Capacity)
        //        {
        //            // Found the needle from the haystack!
        //            return i - haystack.ReaderIndex;
        //        }
        //    }
        //    return -1;
        //}
    }

修改通道代码

 bootstrap.Option(ChannelOption.SoBacklog, 100).Handler(new LoggingHandler("SRV-LSTN"))
                    .ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        pipeline.AddLast(new LoggingHandler("SRV-CONN"));
                        pipeline.AddLast("BeiDouFrameDecoder", new BeiDouFrameDecoder(0x7e, 2048, 12));
                        pipeline.AddLast("ServerClientHandler", new DBServerClientHandler());
                    }));

测试结果

分包.png

水平有限,欢迎指正。谢谢。

猜你喜欢

转载自www.cnblogs.com/zhongzw/p/10422090.html