DotNetty 使用ByteToMessageDecoder 国家部标808协议封装
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协议封装的更多相关文章
- 基于Java Netty框架构建高性能的部标808协议的GPS服务器
使用Java语言开发一个高质量和高性能的jt808 协议的GPS通信服务器,并不是一件简单容易的事情,开发出来一段程序和能够承受数十万台车载接入是两码事,除去开发部标808协议的固有复杂性和几个月长周 ...
- 基于Java Mina框架的部标808服务器设计和开发
在开发部标GPS平台中,部标808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言. 我们为客户开发的部标服务器基于Min ...
- 出租车Jt/T 905协议与部标1078协议融合的网约车视频监控平台
出租车jt/t 905协议,是jt/t 808协议的一个变种,设计者将部标808协议拿过来,并不是单纯的增加网约车相关的指令集,而且对原有的指令如定位0×0200指令也进行了修改,经过一通剧烈的修改, ...
- 基于Redis构建10万+终端级的高性能部标JT808协议的Gps网关服务器(转)
原文地址:http://www.jt808.com/?p=1282 在开发一个大规模的部标GPS监控平台的时候,就算我们花费再多的时间设计和规划,我们也并不能准确的预测出自己未来的车载终端接入量有多大 ...
- 基于Html5+HLS协议播放符合部标1078协议的实时流媒体视频
由于现在主流的部标GPS和1077视频监控平台,都是BS架构,在网页上播放视频,早期的很多平台用的都是ActiveX控件的形式,依赖于IE浏览器,需要降低浏览器的安全设置,而且非常难用.同时由于win ...
- 路由器配置深入浅出—路由器接口PPP协议封装及PAP和CHAP验证配置
知识域: 是针对点对点专线连接的接口的二层封装协议配置 PPP的PAP和CHAP验证,cpt支持,不一定要在gns3上做实验. 路由器出厂默认是hdlc封装,修改为ppp封装后,可以采用pap验证或者 ...
- 开源 DotNetty 实现的 Modbus TCP/IP 协议
本项目的目的是为了学习 DotNetty 与 Modbus 协议,参考 modjn 实现功能 0x01: Read Coils (读取线圈/离散量输出状态) 0x02: Read Discrete I ...
- 如何利用UDP协议封装一个数据包
在如何封装一个数据包上,是一个非常细致的问题,而利用UDP协议来封装的话,是比较简单,让我们一步步来分析典型的TCP/IP协议.一般来说一个典型的一个数据包,包括以太网MAC头+网络层IP数据头+传输 ...
- 基于JT/T 1078协议设计和开发部标视频服务器
交通部与2016年10月份推出了JT/T 1078-2016标准,全称是<道路运输车辆卫星定位系统视频通信协议>.该标准将改变以往两客一危车辆的视频监控设备通信协议都是设备厂商私有协议的局 ...
随机推荐
- Linux配置Hadoop 常用的命令
uname -a 看主机位数 ip a 看IP地址 vi /etc/sysconfig/network 改主机的名字 vi /etc/hosts 改映射关系 vi /etc/sysconfig/net ...
- 神龟快跑,2016做的一款UWP游戏
神龟快跑,2016做的一款UWP游戏, 实际是H5页面, 用LAYA转AS3得到的 安装地址 https://www.microsoft.com/zh-cn/store/p/神龟快跑/9nblggh4 ...
- SSH框架整合过程总结
---------------------siwuxie095 SSH 框架整合过程总结 (一)导入相关 jar 包(共 ...
- WebMagic写的网络爬虫
一.前言 最近因为有爬一些招聘网站的招聘信息的需要,而我之前也只是知道有“网络爬虫”这个神奇的名词,具体是什么.用什么实现.什么原理.如何实现比较好都不清楚,因此最近大致研究了一下,当然,研究的并不是 ...
- struts框架之总结OGNL表达式的特殊的符号
1. # 符号的用法 * 获得contextMap中的数据 > <s:property value="#request.name"/> > <s:pr ...
- 别人家的PS系列又来了!!!
又到了“别人的PS”系列的日常感叹了,大家请边看推文边组织语言准备留言,用点新鲜词,不要再说什么给跪了,献上膝盖之类的,争取换点词. 好了,废话不多说,开始正文,先看几则简单的PS作品: 这两组作品出 ...
- 2018.10.15 NOIP训练 水流成河(换根dp)
传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...
- Django入门与实践-第11章:URL 分发(完结)
http://127.0.0.1:8000http://127.0.0.1:8000/boards/1/http://127.0.0.1:8000/boards/2/http://127.0.0.1: ...
- java中File的delete和deleteOnExit区别(转)
Java的File类中有两个delete方法:delete和deleteOnExit delete无需解释,为直接删除,deleteOnExit文档解释为:在虚拟机终止时,请求删除此抽象路径名表示的文 ...
- Excel获得焦点变色
1. 点击 Sheet 2. 右键菜单 查看代码 3. 复制如下代码 Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Ran ...
