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

一、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博客

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值