SuperSocket 提供了一些通用的协议解析工具, 你可以用他们简单而且快速的实现你自己的通信协议:

  • TerminatorReceiveFilter (SuperSocket.SocketBase.Protocol.TerminatorReceiveFilter, SuperSocket.SocketBase)
  • CountSpliterReceiveFilter (SuperSocket.Facility.Protocol.CountSpliterReceiveFilter, SuperSocket.Facility)
  • FixedSizeReceiveFilter (SuperSocket.Facility.Protocol.FixedSizeReceiveFilter, SuperSocket.Facility)
  • BeginEndMarkReceiveFilter (SuperSocket.Facility.Protocol.BeginEndMarkReceiveFilter, SuperSocket.Facility)
  • FixedHeaderReceiveFilter (SuperSocket.Facility.Protocol.FixedHeaderReceiveFilter, SuperSocket.Facility)

由于本次项目涉及的通信协议是头部格式固定并且包含内容长度的协议这里主要讲解使用FixedHeaderReceiveFilter来拆解.

通信协议格式如下:

 
代码 字节数 说明
68H 1 帧起始码
DLC 4 设备逻辑地址
SEQ 2 主站地址与命令序号
68H 1 帧起始码
C  1 控制码
L 2 数据长度(DATA长度)
DATA 变长 数据内容
CS 1 校验码
16H 1 结束码

在FixedHeaderReceiveFilter,头部指数据内容之前的数据(即数据长度L之前的部分),以上协议可以知道,头部包含11个字节.

首先,根据协议的需要来定义自己的请求类型,先实现一个客户端请求的实体类RequestInfo,改RequestInfo类必须实现接口 IRequestInfo,该接口只有一个名为"Key"的字符串类型的属性.SuperSocket设计了两个RequestInfo类:StringRequestInfo 和BinaryRequestInfo,这里我们自定义一个来GDProtocolRequestInfo实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SuperSocket.SocketBase.Protocol; namespace GDServer
{ public class GDProtocolRequestInfo : IRequestInfo
{
/// <summary>
/// [不使用]
/// </summary>
public string Key { get; set; } /// <summary>
/// 设备逻辑地址
/// </summary>
public string DeviceLogicalCode { get; set; } /// <summary>
/// 命令序列号
/// </summary>
public string Seq { get; set; } /// <summary>
/// 控制码
/// </summary>
public string ControlCode { get; set; } /// <summary>
/// 数据长度
/// </summary>
public string Length { get; set; } /// <summary>
/// 数据域
/// </summary>
public string Data { get; set; } /// <summary>
/// CS校验
/// </summary>
public string Cs { get; set; } /// <summary>
/// 当前完整帧
/// </summary>
//public string EntireFrame { get; set; }
}
}

然后设计基于类FixedHeaderReceiveFilter实现自己的接收过滤器GDProtocolReceiveFilterV2,主要实现GetBodyLengthFromHeader和ResolveRequestInfo方法,实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.Facility.Protocol;//
using SuperSocket.Common;// namespace GDServer
{
/// <summary>
/// 广东规约过滤器V2,(帧格式为GDProtocolRequestInfo)
/// </summary>
public class GDProtocolReceiveFilterV2 : FixedHeaderReceiveFilter<GDProtocolRequestInfo>
{
public GDProtocolReceiveFilterV2()
: base()
{ } /// <summary>
/// 获取数据域和结尾字节长度
/// </summary>
/// <param name="header"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
/// <returns></returns>
protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
{
//length为头部(包含两字节的length)长度 //获取高位
byte high = header[offset + length - ];
//获取低位
byte low = header[offset + length - ];
int len = (int)high * + low;
return len + ;//结尾有2个字节
} /// <summary>
/// 实现帧内容解析
/// </summary>
/// <param name="header"></param>
/// <param name="bodyBuffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
/// <returns></returns>
protected override GDProtocolRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
{
GDProtocolRequestInfo res = new GDProtocolRequestInfo();
string entireFrame = BytesToHexStr(header.Array) + BytesToHexStr(bodyBuffer.CloneRange(offset, length));
//res.EntireFrame = entireFrame;
res.DeviceLogicalCode = entireFrame.Substring(, );
res.Seq = entireFrame.Substring(, );
res.ControlCode = entireFrame.Substring(, );
res.Length = entireFrame.Substring(, );
int dataLen = int.Parse(HEXtoDEC(ReverseHexString(res.Length)));
res.Data = entireFrame.Substring(, dataLen * );
res.Cs = entireFrame.Substring( + dataLen * , );
return res;
} /// <summary>
/// 高低对调
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
string ReverseHexString(string str)
{
char[] buff = new char[str.Length];
for (int i = ; i < str.Length; i += )
{
buff[i] = str[str.Length - i - ];
buff[i + ] = str[str.Length - - i];
}
string s = new string(buff);
return s;
} /// <summary>
/// 16进制转10进制
/// </summary>
/// <param name="HEX"></param>
/// <returns></returns>
string HEXtoDEC(string HEX)
{
return Convert.ToInt64(HEX, ).ToString();
} /// <summary>
/// 转化bytes成16进制的字符
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
string BytesToHexStr(byte[] bytes)
{
string returnStr = "";
if (bytes != null)
{
for (int i = ; i < bytes.Length; i++)
{
returnStr += bytes[i].ToString("X2");
}
}
return returnStr;
}
}
}

先创建新的AppSession,GDProtocolSessionV2,新的AppServer将使用GDProtocolSessionV2.GDProtocolSessionV2代码如下:

using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using System; namespace GDServer
{
public class GDProtocolSessionV2 : AppSession<GDProtocolSessionV2, GDProtocolRequestInfo>
{
protected override void HandleException(Exception e)
{ }
}
}

使用该协议的方法是使用接收或者自己定义的接收过滤器工厂来在 SuperSocket 中启用该协议

using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol; namespace GDServer
{
public class GDProtocolServerV2 : AppServer<GDProtocolSessionV2, GDProtocolRequestInfo>
{
public GDProtocolServerV2()
: base(new DefaultReceiveFilterFactory<GDProtocolReceiveFilterV2, GDProtocolRequestInfo>()) //使用默认的接受过滤器工厂 (DefaultReceiveFilterFactory)
{
}
}
}

这样,GDProtocolServerV2就完成了,下面是测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GDServer;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
var gdServer = new GDProtocolServerV2();
gdServer.Setup();
gdServer.NewSessionConnected += gdServer_NewSessionConnected;
gdServer.NewRequestReceived += gdServer_NewRequestReceived;
gdServer.SessionClosed += gdServer_SessionClosed;
gdServer.Start();
Console.WriteLine("server is:" + gdServer.State.ToString());
while (true)
{
if (Console.ReadKey().KeyChar == 'q')
{
gdServer.Stop();
gdServer.Dispose();
return;
}
}
} static void gdServer_SessionClosed(GDProtocolSessionV2 session, SuperSocket.SocketBase.CloseReason value)
{
Console.WriteLine(session.RemoteEndPoint.ToString() + " closed. reason:" + value);
} static void gdServer_NewRequestReceived(GDProtocolSessionV2 session, GDProtocolRequestInfo requestInfo)
{
var info = requestInfo;
Console.WriteLine("receive from: " + session.RemoteEndPoint.ToString());
Console.WriteLine("DeviceLogicalCode:" + info.DeviceLogicalCode);
Console.WriteLine("Seq:" + info.Seq);
Console.WriteLine("ControlCode:" + info.ControlCode);
Console.WriteLine("Length:" + info.Length);
Console.WriteLine("Data:" + info.Data);
Console.WriteLine("Cs:" + info.Cs);
Console.WriteLine("-------------------------------------------------------------");
} static void gdServer_NewSessionConnected(GDProtocolSessionV2 session)
{
Console.WriteLine(session.RemoteEndPoint.ToString() + " connected.");
}
}
}

分别发送符合该协议格式的帧(用TCP调试助手使用hex方式发送)

68 77 77 12 34 00 01 68 A1 03 00 11 11 11 DC 16

68 77 77 12 34 41 01 68 01 0C 00 01 00 00 00 00 00 00 00 30 80 10 80 94 16

68 77 77 12 34 41 01 68 88 08 00 00 00 30 80 00 10 80 00 16 16

68 77 77 12 34 41 01 68 95 23 00 00 0B 00 00 10 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 5B 00 00 00 00 00 00 00 00 00 00 00 00 00 32 9E 16

打印结果如下:

server is:Running
127.0.0.1:34360 connected.
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:0001
ControlCode:A1
Length:0300
Data:111111
Cs:DC
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:01
Length:0C00
Data:010000000000000030801080
Cs:94
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:88
Length:0800
Data:0000308000108000
Cs:16
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:95
Length:2300
Data:000B0000100000000000FFFFFFFFFFFFFFFF00005B0000000000000000000000000032
Cs:9E
-------------------------------------------------------------

以上代码请自行引入SuperSocket的dll和System.configuration.dll

本文由http://www.cnblogs.com/xiepeixing/原创,转载请著名出处

SuperSocket 1.6.4 通过FixedHeaderReceiveFilter解析自定义协议的更多相关文章

  1. 【Java TCP/IP Socket】构建和解析自定义协议消息(含代码)

    在传输消息时,用Java内置的方法和工具确实很用,如:对象序列化,RMI远程调用等.但有时候,针对要传输的特定类型的数据,实现自己的方法可能更简单.容易或有效.下面给出一个实现了自定义构建和解析协议消 ...

  2. 使用SuperSocket实现自定义协议C/S设计

    一.简介: 21世纪是出于互联网+的时代,许多传统行业和硬件挂钩的产业也逐步转向了系统集成智能化,简单来说就是需要软硬件的结合.这时,软硬件通讯便是这里面最主要的技术点,我们需要做到的是让硬件能够听懂 ...

  3. SuperSocket使用 IRequestInfo 和 IReceiveFilter 等对象实现自定义协议

    为什么你要使用自定义协议? 通信协议用于将接收到的二进制数据转化成您的应用程序可以理解的请求. SuperSocket提供了一个内置的通信协议“命令行协议”定义每个请求都必须以回车换行"\r ...

  4. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  5. Android ViewDragHelper完全解析 自定义ViewGroup神器

    Android ViewDragHelper完全解析 自定义ViewGroup神器   转载请标明出处: http://blog.csdn.net/lmj623565791/article/detai ...

  6. netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端

    本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...

  7. 物联网架构成长之路(35)-利用Netty解析物联网自定义协议

    一.前言 前面博客大部分介绍了基于EMQ中间件,通信协议使用的是MQTT,而传输的数据为纯文本数据,采用JSON格式.这种方式,大部分一看就知道是熟悉Web开发.软件开发的人喜欢用的方式.由于我也是做 ...

  8. 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  9. Netty自定义协议解析原理与应用

    目前,大家都选择Netty做为游戏服务器框架网络通信的框架,而且目前也有很多优秀的产品是基于Netty开发的.它的稳定性,易用性和高效率性已得到广泛的认同.在游戏服务器开发中,选择netty一般就意味 ...

随机推荐

  1. jQuery/javascript实现网页注册的表单验证

    <html> <head> <meta charset="utf-8"> <title>注册表单验证</title> & ...

  2. web前端基础——jQuery编程基础

    1 jQuery简介 jQuery是一个兼容多浏览器的JavaScript库,核心理念是write less,do more(写得更少,做得更多).它对JavaScript进行了封装,使开发更便捷,并 ...

  3. Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP

    使用Portlet filters过滤器做切面AOP Portlet Filters定义于JSR286 Java Portlet Specification 2.0 Portlet Filters是为 ...

  4. log4qt的使用

    Log4Qt替换成新版本使其支持Qt5:https://github.com/devbean/log4qt/tree/master/src/log4qt 1. 解压log4qt到目标文件夹,如D:\Q ...

  5. 关于iReport报表的分页

    问题:二手车认证系统的检测报告采用iReport开发,开发者自定义了一张超级长的纸张,导致打印时自动缩放到了一张A4纸上.需要修改使之能够合理的分页打印,这是来到新公司的第一个任务. 解决方案一: 1 ...

  6. 开发ERP软件应该遵守的22条规则

    总结一下做管理软件,有哪些项是经过检验的条款,必须遵守的. 界面篇 1  要保存用户的偏号(profile/favourite). ASP.NET 2.0引入此功能,当用户修改默认的控件的属性时,框架 ...

  7. FreeSwitch安装配置记录

    安装FreeSwitch 主要命令如下: git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.gitcd freeswitch/. ...

  8. Windows7下面exe寄宿WCF:Http无法注册URL{0} ,进程不具有此命名空间的访问权限问题

    运行寄宿exe程序的时候通过run as administrator来启动就OK了.

  9. Oracle Redo Log 机制 小结(转载)

    Oracle 的Redo 机制DB的一个重要机制,理解这个机制对DBA来说也是非常重要,之前的Blog里也林林散散的写了一些,前些日子看老白日记里也有说明,所以结合老白日记里的内容,对oracle 的 ...

  10. 用Storm轻松实时大数据分析【翻译】

    原文地址 简单易用,Storm让大数据分析变得轻而易举. 如今,公司在日常运作中经常会产生TB(terabytes)级的数据.数据来源包括从网络传感器捕获的,到Web,社交媒体,交易型业务数据,以及其 ...