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. Partial Tree(DP)

    Partial Tree http://acm.hdu.edu.cn/showproblem.php?pid=5534 Time Limit: / MS (Java/Others) Memory Li ...

  2. Maven项目整合Struts2框架

    -------------------------siwuxie095                                 Maven 项目整合 Struts2 框架         1. ...

  3. [leetcode]333. Largest BST Subtree最大二叉搜索树子树

    Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest mea ...

  4. 44-python-三维画图

    https://www.cnblogs.com/xingshansi/p/6777945.html python绘制三维图   作者:桂. 时间:2017-04-27  23:24:55 链接:htt ...

  5. 7-qt随机数qrand

    QT生成随机数和C语言差距不大,C语言用srand()和rand(),QT是用Qsrand()和qrand(): QT生成随机数的格式是: qsrand(QTime(0,0,0).secsTo(QTi ...

  6. linux下安装memcached以及扩展(xampp环境)

    网上有很多相关的文章,就不具体写了.(假设这里文件都上传到更目录下的tmp文件夹下) 1.大致流程先装 libevent 和 memcache http://www.cnblogs.com/zgx/a ...

  7. 坑爹的HP

    昨天晚上帮人远程修理电脑,情况是这样的: HP CQ45笔记本, 比较老的机器, win32 xp sp3 系统, 突然发现没有声音了,而且右下角也没有出现小喇叭图标. 处理过程: 1.先查看了控制面 ...

  8. 判断浏览器是ie9座特殊处理

    function ie(){ var agent = navigator.userAgent.toLowerCase();//判断浏览器版本 return (!!window.ActiveXObjec ...

  9. ObjC.instancetype

    1. instancetype http://nshipster.com/instancetype/ 2. Objc的扩展 http://clang.llvm.org/docs/LanguageExt ...

  10. 我的UI启蒙之路

    为什么叫UI启蒙之路呢? 我没有学过美术,也不懂设计,但是有的时候也许就是一种命中注定吧,让我知道了UI,并且一发不可收拾的爱上了它. 具体情况是这样的: 我毕业于电力学校,是一名不折不扣的工科生,专 ...