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. fir.im Weekly - 工欲善其事,必先利其器

    这周为大家搜罗了一些优秀的 GitHub 资源.APP开发工具.产品UI设计资源等等,同时也有一些程序员个人成长的Tips,"软硬件兼备"也许事半功倍不只是梦! Open-Sour ...

  2. iOS开发---百度地图配置流程,2.6.0 版本 支持64位

      1.首先需要在百度地图下载最新SDK:地址: http://developer.baidu.com/map/index.php?title=iossdk/sdkiosdev-download 2. ...

  3. Leetcode 119 Pascal's Triangle II 数论递推

    杨辉三角,这次要输出第rowIndex行 用滚动数组t进行递推 t[(i+1)%2][j] = t[i%2][j] + t[i%2][j - 1]; class Solution { public: ...

  4. ES6类与模块

    class Animal { // 构造方法,实例化的时候会被调用,如果不指定,那么会有一个不带参数的默认构造函数 constructor(name, color) { this.name = nam ...

  5. PHP之算法偶遇隨感

    php真的很棒,很多函數把我們想要的功能都簡單實現了,是項目快速開發的首選.說實話,在BS程序開發方面我認為最好的兩種語言是PHP和JSP,我之前曾學過一段時間的java,確實很棒完全的OOP,但是它 ...

  6. AsyncTask实现多线程断点续传

    前面一篇博客<AsyncTask实现断点续传>讲解了如何实现单线程下的断点续传,也就是一个文件只有一个线程进行下载.   对于大文件而言,使用多线程下载就会比单线程下载要快一些.多线程下载 ...

  7. Hadoop-2.6.0 + Zookeeper-3.4.6 + HBase-0.98.9-hadoop2环境搭建示例

    1    基本信息 1.1     软件信息 hadoop-2.6.0 zookeeper-3.4.6 hbase-0.98.9-hadoop2 (以下示例中使用的操作系统是Centos 6.5,请将 ...

  8. crond: unrecognized service 无crond解决办法

    运行计划任务时:service crond restart提示:crond: unrecognized service安装计划任务:yum -y install vixie-cron 另外附计划任务的 ...

  9. Codeforces Round #382 (Div. 2) D. Taxes 哥德巴赫猜想

    D. Taxes 题目链接 http://codeforces.com/contest/735/problem/D 题面 Mr. Funt now lives in a country with a ...

  10. HLS视频点播&直播初探

    前端可选的视频直播协议大致只有两种: RTMP(Real Time Messaging Protocol) HLS(HTTP Live Streaming) 其中RTMP是Adobe开发的协议,无法在 ...