SuperSocket: FixedHeaderReceiveFilter协议模版

        SuperSocket 提供了几种通用的协议解析工具,比如上一篇文章用到的结束符过滤器:TerminatorReceiveFilter (TerminatorReceiveFilterFactory)。

        通常,如果传输数据而不是简单的命令,使用FixedHeaderReceiveFilter(头部格式固定并且包含内容长度的协议过滤器)会更加普遍。

1.定义帧格式

通常,定义帧的格式,大都是类似下面这种格式

    

按照FixedHeaderReceiveFilter的规则,则可将此帧格式解析为


     

        根据此帧格式自定义一个请求消息

    public  struct  constNum 
    {
        public const int Headerlen = 5; //头长度
        public const int lenloc = 5;    //指示长度所在位置
    }
    /*
    public struct  frameHeaderFormat
    {
        public byte start ;     //前导码
        public byte dstaddr;    //目的地址
        public byte srcaddr;    //源地址
        public byte func;       //功能码
        public byte datalen ;   //数据长度(字节)
       
    }
    */
    public class MyRequestInfo : IRequestInfo
    {
        public string Key { get; set; }
        public byte start;     //前导码
        public byte dstaddr;    //目的地址
        public byte srcaddr;    //源地址
        public byte func;       //功能码
        public byte datalen;   //数据长度(字节)
        public List<byte> data = new List<byte>(); //数据内容
        public MyRequestInfo(byte[] header, byte[] bodyBuffer, int length) 
        {
            start = header[0];
            dstaddr = header[1];
            srcaddr = header[2];
            func = header[3 ];
            datalen = (byte)length ;
            data = bodyBuffer.ToList();
        }

2.过滤器

        使用:头部格式固定并且包含内容长度的协议过滤器

    public class MyReceiveFilter : FixedHeaderReceiveFilter<MyRequestInfo>
    {
        public MyReceiveFilter()
            : base(constNum.Headerlen)
        {

        }

        protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
        {
            return (int)header[offset + length - 1];
        }

        protected override MyRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
        {
            byte[] bb   = new byte[length] ;
            Array.Copy(bodyBuffer, offset, bb, 0, length);
            return new MyRequestInfo(header.Array, bb, length);
        }
    }

3.其他代码

        会话控制类,服务器类

    public class MYSession : AppSession<MYSession, MyRequestInfo>
    {
        
        public int ID { get; set; }
        /// <summary>
        /// 用户连接会话
        /// </summary>
        protected override void OnSessionStarted()
        {
            Console.WriteLine("New Request");
            base.OnSessionStarted();
        }

        /// <summary>
        /// 未知的用户请求命令
        /// </summary>
        /// <param name="requestInfo"></param>
        protected override void HandleUnknownRequest(MyRequestInfo requestInfo)
        {
            base.HandleUnknownRequest(requestInfo);
        }

        protected override void OnSessionClosed(CloseReason reason)
        {
            Console.WriteLine("会话关闭");
            base.OnSessionClosed(reason);
        }
    }
    public class MYServer : AppServer<MYSession, MyRequestInfo>
    {
        
        public MYServer()
            : base(new DefaultReceiveFilterFactory<MyReceiveFilter, MyRequestInfo>())
        { 
           
        }
    }

在程序合适的地方添加

  public MYServer appServer = new MYServer();
  appServer.NewRequestReceived +=  appServer_NewRequestReceived ;
            if (!appServer.Setup(60000)) //开启的监听端口
            {
                Console.WriteLine("Failed to Setup!");
                return;
            }
            if (!appServer.Start())
            {
                Console.WriteLine("Failed to Start!");
                return;
            }
            Console.WriteLine("The server started successfully.");

实现接收请求函数

        int   cnt=0;
        void appServer_NewRequestReceived(MYSession session, MyRequestInfo requestInfo)
        {
            var info = requestInfo;
            this.BeginInvoke  
            (
                 (ThreadStart)delegate()
                 {    //显示数据
                      textBox_recv.Text = "dstaddr:" + info.dstaddr.ToString();
                      textBox_recv.Text += "\r\nsrcaddr:" + info.srcaddr.ToString();
                      textBox_recv.Text += "\r\n:" + System.Text.Encoding.Default.GetString(info.data.ToArray()) + "\r\n";
                      label_cnt.Text = (++cnt).ToString();
                 }
            );
            
        }

4.测试

使用Socket 调试工具,创建Client,端口60000

发送数据进行测试


为了方便,我使用文本发送方式。前5个空格加后面32个字符。空格的ascii码值为32,所以如上面所示。

假如发送端的数据出现丢失,错误会一直累积下去,除非重新启动服务。所以这种程序并不稳健。实际项目中不建议使用这种方法。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值