基于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模板协议FixedHeaderReceiveFilter与msgpack结合

实现SuperSocket模板协议FixedHeaderReceiveFilter与msgpack结合在群里有个群友在群里一直在问使用FixedHeaderReceiveFilter与msgpack结...
  • a888880
  • a888880
  • 2015年09月24日 01:16
  • 2298

SuperSocket入门(五)-常用协议实现模版及FixedSizeReceiveFilter示例_0

Socket里面的协议解析是Socket通讯程序设计中最复杂的地方,如果你的应用层协议设计或实现不佳,Socket通讯中常见的粘包,分包就难以避免。SuperSocket内置了命令行格式的协议Comm...
  • muzili12a3
  • muzili12a3
  • 2017年01月27日 12:18
  • 456

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

效果:禁止未被授权的连接执行某些命令,这里使用验证登陆为例。   1.      在MySession中添加bool类型的变量isLogin:   2.      创建类MyCommandFilter...
  • kuanzai123
  • kuanzai123
  • 2013年12月18日 23:31
  • 4326

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

服务器效果截图:   客户端效果截图:   1.      创建控制台项目,导入SuperSocket.Common、SuperSocket.SocketBas...
  • u011470119
  • u011470119
  • 2014年09月22日 22:21
  • 3800

使用开源的supersocket实现的路灯模拟通信

  • 2013年09月15日 08:44
  • 5.86MB
  • 下载

superSocket和android的通讯

使用superSocket做服务端,android作客户端,android实现登录功能 superSocket的配置请看官网 服务端,新建登录命令 如下 public class LO...
  • shizhen_2012
  • shizhen_2012
  • 2016年09月02日 15:00
  • 2451

java自定义filter

 Filter过滤器   使用Filter分为两部分:编写Filter和配置Filter。   1.编写Filter:      1)实现 javax.servlet.Filter ...
  • su513292239
  • su513292239
  • 2016年03月29日 09:08
  • 903

SuperSocket框架命令不被识别的一种原因

在使用Supersocket实现毕业设计服务器过程中,遇到Command无法被识别的问题,记录如下: 通过Debug调试,发现数据可以传递到服务器,并且被协议正确解析。也就是说,生成了正确的自定义...
  • snowin1994
  • snowin1994
  • 2017年04月30日 04:53
  • 581

SuperSocket服务器架设(一):认识SuperSocket

SuperSocket官方介绍: SuperSocket is alight weight, cross platform and extensible socket server applicati...
  • kuanzai123
  • kuanzai123
  • 2013年11月28日 22:23
  • 10807

SuperSocket服务器架设(三):在SuperSocket中自定义Command、AppServer和AppSession

SuperSocket
  • u011470119
  • u011470119
  • 2014年09月22日 22:22
  • 2586
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于SuperSocket 1.6版本的自定义帧过滤的源码分析
举报原因:
原因补充:

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