基于SuperSocket 1.6版本的自定义帧过滤的源码分析(实现MODBUS通信)

2023-11-11

一、SuperSocket 1.6 自定义帧过滤的官方文档地址

http://docs.supersocket.net/v1-6/zh-CN/Implement-Your-Own-Communication-Protocol-with-IRequestInfo,-IReceiveFilter-and-etc

二、此博客的内容

        博文描述如何根据官方的模板,实现自己的基于MODBUS的通信帧的过滤。

三、接口及其作用

        没有内容

四、实现方法

1、继承FixedHeaderReceiveFilter类

public class MyReceiveFilter : FixedHeaderReceiveFilter<MyRequestInfo>
    {
        public MyReceiveFilter()
            :base(3)
        {        }

2、实现2个重载函数

protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
        {
            if (header.Length >= offset + 2)
            {
                //length为头部(包含1字节的Length长度)
                byte data = header[offset+2];
                int len = (int)data+2;
                //int len = (int)data;
                return len;
            }
            else
                return -1;
        }

 

protected override MyRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
        {
            byte[] buffer = new byte[header.Array.Length + length];
            Buffer.BlockCopy(header.Array, 0, buffer, 0, header.Array.Length);
            Buffer.BlockCopy(bodyBuffer, offset, buffer, header.Array.Length, length);
            if (true == CRC16.VerifyFrame(buffer, 0, (uint)buffer.Length))
            {
                MyRequestInfo res = new MyRequestInfo();
                string entireFrame = BytesToHEXStr(header.Array) + BytesToHEXStr(bodyBuffer.CloneRange(offset, length));
                res.DeviceLogicalCode = entireFrame.Substring(0, 2);
                res.Seq = entireFrame.Substring(2, 2);
                res.Length = entireFrame.Substring(4, 2);
                int dataLen = int.Parse(HEXtoDEC(res.Length));
                res.Data = entireFrame.Substring(6, dataLen * 2);
                res.Crc = entireFrame.Substring(6 + dataLen * 2, 4);
                /*将数据更新到链表*/
                List<int> lst_data = new List<int>();
                dataLen /= 2;
                for (int i = 0; i < dataLen; i++)
                {
                    int val = ((int)bodyBuffer[offset + 2*i]) * 256 + bodyBuffer[offset + 2*i + 1];
                    if (val > 0x8000)/*是个负数*/
                        val = (0x8000-(val - 0x8000) + 1);
                    lst_data.Add(val);
                }
                res.DataArray = lst_data;
                return res;/*解析出1个完整的帧,则返回实例*/
            }
            else { return null;/*此缓冲区中并不包含一个完整的帧,则返回 NULL*/ }
        }

五、具体的程序运行流程解析

1、自定义帧过滤的上层处理函数的关键代码在 AppSession.cs文件中。
2、当接收到帧之后,程序的调用流程是
IAppSession.ProcessRequest()->FilterRequest()->自定义的帧过滤函数
3、IAppSession.ProcessRequest()部分代码及注释

int IAppSession.ProcessRequest(byte[] readBuffer, int offset, int length, bool toBeCopied)
        {
            int rest, offsetDelta;

            while (true)
            {/*这里有一个死循环,正常情况下,在rest<=0的时候会跳出,所以,在Filter()中,只要数据流处理完了,不管是否有效,都要让rest为0*/
                var requestInfo = FilterRequest(readBuffer, offset, length, toBeCopied, out rest, out offsetDelta);

                if (requestInfo != null)
                {
                    try
                    {
                        AppServer.ExecuteCommand(this, requestInfo);
                    }
                    catch (Exception e)
                    {
                        HandleException(e);
                    }
                }

                if (rest <= 0)
                {
                    return offsetDelta;
                }

                //Still have data has not been processed
                offset = offset + length - rest;
                length = rest;
            }
        }

        #endregion
    }

TRequestInfo FilterRequest(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest, out int offsetDelta)
        {
            if (!AppServer.OnRawDataReceived(this, readBuffer, offset, length))/*没进去看是干嘛的*/
            {
                rest = 0;
                offsetDelta = 0;
                return null;
            }

            var currentRequestLength = m_ReceiveFilter.LeftBufferSize;/*当前请求的长度,即未处理的数据流长度*/

            var requestInfo = m_ReceiveFilter.Filter(readBuffer, offset, length, toBeCopied, out rest);

            if (m_ReceiveFilter.State == FilterState.Error)
            {/*如果你在自定义的解析函数里面,返回了帧错误,则会进入这里,关闭连接,并返回*/
                rest = 0;
                offsetDelta = 0;
                Close(CloseReason.ProtocolError);
                return null;
            }

            var offsetAdapter = m_ReceiveFilter as IOffsetAdapter;

            offsetDelta = offsetAdapter != null ? offsetAdapter.OffsetDelta : 0;

            if (requestInfo == null)
            {/*如果未解析出一个完整的帧,则让 请求长度 等于 剩余长度(LeftBufferSize与rest的区别在前面提过)*/
                //current buffered length
                currentRequestLength = m_ReceiveFilter.LeftBufferSize;
            }
            else
            {/*更新 当前请求长度*/
                //current request length
                currentRequestLength = currentRequestLength + length - rest;
            }

            if (currentRequestLength >= AppServer.Config.MaxRequestLength)
            {
                if (Logger.IsErrorEnabled)
                    Logger.Error(this, string.Format("Max request length: {0}, current processed length: {1}", AppServer.Config.MaxRequestLength, currentRequestLength));
                Close(CloseReason.ProtocolError);
                return null;
            }

            //If next Receive filter wasn't set, still use current Receive filter in next round received data processing
            if (m_ReceiveFilter.NextReceiveFilter != null)
                m_ReceiveFilter = m_ReceiveFilter.NextReceiveFilter;

            return requestInfo;
        }

 (1条消息) 基于SuperSocket 1.6版本的自定义帧过滤的源码分析_chxaitz的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于SuperSocket 1.6版本的自定义帧过滤的源码分析(实现MODBUS通信) 的相关文章

随机推荐

  • 通过修改kong属性解决不能获取外网域名的问题

    作者 朱金灿 来源 https blog csdn net clever101 kong就是对nginx进行再一次封装而做成的企业级api网关 kong dashboard是kong进行设置的一个可视化界面 目前公司的服务集群都采用kong
  • 开发中 @/方式引入的文件,通过ctrl + 点击可直接指向

    问题描述 实际开发项目中 例如VUE 或者 React 开发中 我们经常会通过 的方式进行文件引入 但是这种方式会导致不能直接点击进入指定的文件 解决方案 根目录创建jsconfig json文件 文件内容如下 exclude node m
  • Vue实现搜索关键词高亮显示

    最近写移动端项目的时候 遇到搜索关键词高亮的需求 写篇文章纪录一下 先看效果 以上为实现效果展示 整体思路 对后台返回的数据进行操作 我这里是模拟数据 使用正则去匹配搜索关键词后 使用replace进行字符串的替换 渲染数据部分使用v ht
  • CentOS-6.6-x86_64-minimal.iso镜像下载

    CentOS6 6的64位镜像文件iso 迅雷种子 centos是基于linux的内核开发的操作系统 是企业服务器广泛使用的操作系统 链接 https pan baidu com s 1tSpIdAxTnScqXQotVCg2gg http
  • ARM Cortex-A7时钟树综合实战分析

    ARM Cortex A7时钟树综合实战分析 文章右侧广告为官方硬广告 与吾爱IC社区无关 用户勿点 点击进去后出现任何损失与社区无关 吾爱 IC 高端技术交流社区 知识星球目前已经拥有1040 位星球成员 目前数字 IC 领域最大的高端技
  • 判断玩家是否在敌人的可视范围的方法Physics.OverlapSphere

    Physics OverlapSphere Vector 3 position float radius 该方法判断以一个点为中心 半径为radius的球中的碰撞体集合 所以返回值可以用 var 如var colliders Physics
  • spring mvc 控制器返回 HTML 页面

    之前的页面都是 jsp的 后面需要改为html 如下代码 之前的Log 是 jsp 后面改为 html Log html 页面单独运行正常 但是在控制器跳转是出错 如下 RequestMapping value login out publ
  • HCIPR&S222-V2.5一些总结

    1 IP Precedence取值中 代表immediate的是2 2 VRRP中路由器已经为Master设备 不会被更高优先级的Backup设备抢占 如果出现故障的情况会被Backup设备抢占 故障恢复后重新抢占为Master设备 默认为
  • java jmf视频播放器无法播放视频问题

    初学java 谢了一个参照网上代码写了个java jmf视频播放器 运行调试代码没问题 可是被这个avi视频格式纠结的要死 换了n多个avi格式视频依然不行 经过查阅资料发现现在网上流行的avi格式并不是真正的avi格式 大都是其他格式转化
  • 原生AJAX 的基本使用

    1 准备工作 1 1 安装node js Node js 中文网 1 2 安装express 服务端框架 Express 基于 Node js 平台的 web 应用开发框架 Express 中文文档 Express 中文网 1 2 1 初始
  • MYSQL多表连查

    前言 多表查询 也称为关联查询 指两个或更多个表一起完成查询操作 前提条件 这些一起查询的表之间是有关系的 一对一 一对多 它们之间一定是有关联字段 这个关联字段可能建立了外键 也可能没有建立外键 比如 员工表和部门表 这两个表依靠 部门编
  • 诚邀您参加Go+1.0发布会!与大咖共同探索行业生态!

    你想参与iPhone13抽奖吗 你想和大咖面对面交流吗 你想收获最前沿的行业动态吗 10 月15 日 Go Together Go 1 0发布会暨Go 开发者基金会启动仪式重磅来袭 活动中除七牛云 CEO Go 语言发明人许式伟以及Go 开
  • 传奇私服游戏支付接口申请(已解决)

    传奇游戏是一款经典打怪升级 PK游戏 盛大游戏公司于2001年9月发布 随后出现了众多传奇私服游戏版本 到现在依然受很多人喜爱 经历了多次升级换代 现已转变为游戏体验更加细腻的页游和手游 成为了小成本高收益的热门游戏 受到各游戏服务商和玩家
  • IO流基础总结

    IO流 File 1 File类概述和构造方法 File 它是文件和目录路径名的抽象表示 文件和目录是可以通过File封装成对象的 对于File而言 其封装的并不是一个真正存在的文件 仅仅是一个路径名 而已 它可以是存在的 也可以是不存在的
  • Allegro PCB设计中:结构文件DXF导入、更新、PCB板框更改

    1 将结构工程师输出的DXF文件导入到Allegro PCB设计中 文章来源地址https www yii666 com blog 453846 html action onAll 2 结构文件DXF多次更改导致PCB板框尺寸涉及的修改 1
  • C++STL:vector

    C STL中的vector是一种动态分配的数组 可以在运行时动态增加和删除元素 它也是C 中最常用的容器之一 以下是vector的使用介绍 引入头文件 在使用vector之前 需要添加头文件 include
  • nrm 源管理

    什么是nrm nrm 是一个 npm 源管理器 你可以快速地在 npm源间切换 大家在开发中可能会经常切换 npm 源 我们会使用命令切换 如 npm set registry https registry npm taobao org 或
  • Vue style中的 scoped 属性

    Vue 中存在 scoped 属性 HTML5中也存在一个 scoped 属性 而且 这两者都是针对 css 样式处理的属性 所以很多文章在 解释 Vue scoped 的时候 都会把两者混为一谈 直接进把 HTML5 scoped 的定义
  • Login控件用法,用自己的数据库提供login控件的数据源

    一 在配置web config文件 web config 文件
  • 基于SuperSocket 1.6版本的自定义帧过滤的源码分析(实现MODBUS通信)

    一 SuperSocket 1 6 自定义帧过滤的官方文档地址 http docs supersocket net v1 6 zh CN Implement Your Own Communication Protocol with IReq