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

个人博客地址   http://www.dncblogs.cn/Blog/ShowBlog/70

1.国家部标808协议格式

标识位
采用 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, ).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(, 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}),
};
}

4.使用ByteToMessageDecoder,代码如下

/// <summary>
///粘包处理 数据包 头和尾 标志 都包含分割 字符串
/// </summary>
public class BeiDouFrameDecoder : ByteToMessageDecoder
{
private int frameFlag = 0x7e;
private int manFrameLength;
private int minFrameLength;
private int delimiters = ;
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 = -;
//标记
int OriginalReadIndex = input.ReaderIndex;
input.MarkReaderIndex();
if (frameFlag == input.GetByte(OriginalReadIndex))//找到头 第一个字节是头 不改变 ReaderIndex
{
input.SetReaderIndex(OriginalReadIndex + );
readLen = IndexOfEnd(input);
input.ResetReaderIndex();
if (readLen != -)//没有找到尾
{
readLen += delimiters;
if (readLen > manFrameLength || readLen < minFrameLength)
{
input.SkipBytes(readLen);
}
else
{
IByteBuffer frame = input.ReadSlice(readLen);
frame.Retain();
output.Add(frame);
}
}
}
else
{
//找头
int readIndex = -;
int seekReaderIndex = input.ReaderIndex + ;
while (seekReaderIndex < input.WriterIndex)
{
if (frameFlag == input.GetByte(seekReaderIndex))//找到头部
{
readIndex = seekReaderIndex;
break;
}
seekReaderIndex++;
} if (readIndex != -)//找到头
{
if ((input.ReadableBytes - readIndex) < minFrameLength)//可以读取的 数据长度小于最小帧长度,说明还不够一包数据,等下一次再读取
{
input.ResetReaderIndex();//本次跳过 还原ReaderIndex
return;
} input.SetReaderIndex(readIndex + );
readLen = IndexOfEnd(input);
if (readLen == -)//没有找打 尾
{
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 -;
}
}
//Found the needle from the haystack! 找到
return i - haystack.ReaderIndex;
}
return -;
} //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, ).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, , ));
pipeline.AddLast("ServerClientHandler", new DBServerClientHandler());
}));

测试结果

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

DotNetty 使用ByteToMessageDecoder 国家部标808协议封装的更多相关文章

  1. 基于Java Netty框架构建高性能的部标808协议的GPS服务器

    使用Java语言开发一个高质量和高性能的jt808 协议的GPS通信服务器,并不是一件简单容易的事情,开发出来一段程序和能够承受数十万台车载接入是两码事,除去开发部标808协议的固有复杂性和几个月长周 ...

  2. 基于Java Mina框架的部标808服务器设计和开发

    在开发部标GPS平台中,部标808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言. 我们为客户开发的部标服务器基于Min ...

  3. 出租车Jt/T 905协议与部标1078协议融合的网约车视频监控平台

    出租车jt/t 905协议,是jt/t 808协议的一个变种,设计者将部标808协议拿过来,并不是单纯的增加网约车相关的指令集,而且对原有的指令如定位0×0200指令也进行了修改,经过一通剧烈的修改, ...

  4. 基于Redis构建10万+终端级的高性能部标JT808协议的Gps网关服务器(转)

    原文地址:http://www.jt808.com/?p=1282 在开发一个大规模的部标GPS监控平台的时候,就算我们花费再多的时间设计和规划,我们也并不能准确的预测出自己未来的车载终端接入量有多大 ...

  5. 基于Html5+HLS协议播放符合部标1078协议的实时流媒体视频

    由于现在主流的部标GPS和1077视频监控平台,都是BS架构,在网页上播放视频,早期的很多平台用的都是ActiveX控件的形式,依赖于IE浏览器,需要降低浏览器的安全设置,而且非常难用.同时由于win ...

  6. 路由器配置深入浅出—路由器接口PPP协议封装及PAP和CHAP验证配置

    知识域: 是针对点对点专线连接的接口的二层封装协议配置 PPP的PAP和CHAP验证,cpt支持,不一定要在gns3上做实验. 路由器出厂默认是hdlc封装,修改为ppp封装后,可以采用pap验证或者 ...

  7. 开源 DotNetty 实现的 Modbus TCP/IP 协议

    本项目的目的是为了学习 DotNetty 与 Modbus 协议,参考 modjn 实现功能 0x01: Read Coils (读取线圈/离散量输出状态) 0x02: Read Discrete I ...

  8. 如何利用UDP协议封装一个数据包

    在如何封装一个数据包上,是一个非常细致的问题,而利用UDP协议来封装的话,是比较简单,让我们一步步来分析典型的TCP/IP协议.一般来说一个典型的一个数据包,包括以太网MAC头+网络层IP数据头+传输 ...

  9. 基于JT/T 1078协议设计和开发部标视频服务器

    交通部与2016年10月份推出了JT/T 1078-2016标准,全称是<道路运输车辆卫星定位系统视频通信协议>.该标准将改变以往两客一危车辆的视频监控设备通信协议都是设备厂商私有协议的局 ...

随机推荐

  1. 使用CSS实现透明边框的效果——兼容当前各种主流浏览器[xyytIT]

    这个效果可是通过代码实现的哦,在不同浏览器下都可以正常显示 对于html中使用CSS实现透明边框的效果,主要有以下四种属性设置方法,但由于 这些属性兼容性并不是很好,单一使用会造成不同浏览器显示效果不 ...

  2. 不同的路径12障碍物 · Unique Paths12

    [抄题]: 有一个机器人的位于一个 m × n 个网格左上角. 机器人每一时刻只能向下或者向右移动一步.机器人试图达到网格的右下角. 问有多少条不同的路径? [思维问题]: 以为要用count来计数: ...

  3. 12-matlab简单读excel

    数据读入: clc; clear; AllNeedDate = xlsread('E:\a-建模\2018-5月校赛\2018年数学建模校内挑战赛题目\挑战赛A题\附件2:各城镇月度需求数据.xlsx ...

  4. Redis安装异常解决办法

    官网地址:http://redis.io/ 官网下载地址:http://redis.io/download 1. 下载Redis源码(tar.gz),并上传到Linux 2. 解压缩包:tar zxv ...

  5. struts框架值栈问题二之值栈的内部结构

    2. 问题二 : 值栈的内部结构 ? * 值栈由两部分组成 > root -- Struts把动作和相关对象压入 ObjectStack 中--List > context -- Stru ...

  6. 2015湖南湘潭 D 二分

    2015湖南湘潭第七届大学生程序设计比赛 D题 Fraction Accepted : 133   Submit : 892 Time Limit : 1000 MS   Memory Limit : ...

  7. VMware下的Linux系统中Windows的共享目录,不支持创建软连接

    [问题]  在编译VMware下的Linux系统对从Windows中共享过来的文件,进行编译的时候,遇到:  ln: creating symbolic link XXXXXX : Operation ...

  8. [Groovy] List和Map用法搜集

    http://chenfeng0104.iteye.com/blog/609075 http://www.cnblogs.com/muzi1994/p/5169928.html https://zhi ...

  9. 删除pdf文件所有超链接

    最近在读deep learning 书Bengio那本,在Github上面下载的,下载回来全都是超链接, 超级烦,比如点一下梯度下降法,就直接跳转到数后尾的index. 我看书还喜欢老点,所以要把他们 ...

  10. DevExpress VCL 已死-----关于13.1.4的发布。

    随着DevExpress VCL 13.1.4 的发布,已基本上宣布了devexpress vcl 已经死亡了. 除了一些bug 修正,没有什么新的东西,每年的订阅费又那么贵,而且delphi 现在已 ...