基于SuperSocket 1.6版本的自定义帧过滤的源码分析

原创 2016年03月17日 22:17:38

一、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;
        }

相关文章推荐

SuperSocket服务器架设(五):使用命令过滤器

效果:禁止未被授权的连接执行某些命令,这里使用验证登陆为例。   1.      在MySession中添加bool类型的变量isLogin:   2.      创建类MyC...

SuperSocket入门系列-01

说到socket,我们常见的处理方法是使用Socket组件自己去定义监听和处理,如果是在代码量较小的情况下面,使用这种方式可能会得心应手,但是如果遇到大的项目就显得有点力不从心了。这里博主则推荐一款....
  • laymat
  • laymat
  • 2015年10月17日 09:07
  • 9482

SuperSocket服务器架设(二):使用SuperSocket构建简单服务器

服务器效果截图:   客户端效果截图:   1.      创建控制台项目,导入SuperSocket.Common、SuperSocket.SocketBase、SuperSocke...

【Python笔记】源码编译安装Python时,如何支持自定义安装的高版本openssl库

最近有个小需求想使用Scrapy库做抓取,但公司开发机操作系统版本老旧,导致系统默认的openssl库版本也很低(OpenSSL 0.9.7a Feb 19 2003),最终导致安装Scrapy非常麻...
  • slvher
  • slvher
  • 2015年01月02日 22:20
  • 10947

使用SuperSocket实现TLV自定义协议网络通信的Demo

原文地址:http://www.cnblogs.com/liping13599168/archive/2011/07/09/2101064.html  前些天看到江大鱼发布了Supe...

(7) java源码分析------之ArrayList (对应数据结构中线性表中的顺序表,JDK1.6)

ArrayList就是传说中的动态数组,就是Array的复杂版本,它提供了如下一些好处:动态的增加和减少元素、灵活的设置数组的大小......     认真阅读本文,我相信一定会对你有帮助。比如...

Java中ArrayList源码深入分析(JDK1.6)

ArrayList就是传说中的动态数组,就是Array的复杂版本,它提供了如下一些好处:动态的增加和减少元素、灵活的设置数组的大小......     认真阅读本文,我相信一定会对你有帮助。比如为什...

HashMap源码分析(基于JDK1.6)

在Java集合类中最常用的除了ArrayList外,就是HashMap了。本文尽自己所能,尽量详细的解释HashMap的源码。一山还有一山高,有不足之处请之处,定感谢指定并及时修正。     在...

源码分析MyCat----优化篇之支持ER分片多语句插入(基于1.6)

基于MyCat1.6,详细分析了ER分片数据插入过程(路由解析),同时修复支持ER字表多statement语句支持。...

mycat 1.6 源码分析-网络篇

相关资料 源码:https://github.com/MyCATApache/Mycat-Server 权威指南:http://www.mycat.org.cn/document/Mycat_V1...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于SuperSocket 1.6版本的自定义帧过滤的源码分析
举报原因:
原因补充:

(最多只允许输入30个字)