zoukankan      html  css  js  c++  java
  • SuperSocket 介绍

    一、总体介绍

    SuperSocket 是一个轻量级的可扩展的 Socket 开发框架,由江振宇先生开发。

    官方网站:http://www.supersocket.net/

    1、SuperSocket具有如下特点:

    • 简单易用,只需要几个类就能创建出健壮的Socket服务器端程序
    • 性能优良, 稳定可靠
    • 支持各种协议, 内置的协议解析工具让你把实现通信协议这种复杂的工作变得很简单
    • 自动支持SSL/TLS传输层加密
    • 强大,灵活而且可扩展的配置让你开发Socket服务器省时省力
    • 支持多个socket服务器实例运行, 而且支持多个服务器实例的隔离
    • SuperSocket能以控制台或者Windows服务形式运行。一个脚本就能将SuperSocket安装成服务
    • 灵活的日志策略能够记录大部分socket活动
    • 支持UDP
    • 支持IPv6
    • 支持Windows Azure
    • 支持Linux/Unix操作系统(通过Mono 2.10或以上版本)
    • 内置可直接使用的Flash/Silverlight Socket策略服务器

    2、SuperSocket应对项目需求特点:

    1.      开源,基于Apache 2.0协议,可以免费使用到商业项目.
    2.      高性能的事件驱动通信.
    3.      会话级别的发送队列能够让你通过会话并发的发送数据,并保持高性能和可控性.
    4.      强大且高性能的协议解析实现工具帮你简化了网络数据的分析工作.
    5.      轻量级意味着组件可以自由选择使用,可根据环境变化变更.

    3、SuperSocket的架构和设计

     可以在官方的中文文档查询到http://docs.supersocket.net/v1-6/zh-CN/Architecture-Diagrams

    1. 每个连接的客户端都以Session的方式管理,发送数据给客户端也通过Session的Send方法,
    2. 每个客户端发过来的数据流都经过ReceiveFilter过滤器(这里即可自定义协议或者使用自带的一些帧过滤器)到ReqestInfo。
    3. ReqestInfo包含了该条数据内容,当然如果是自定义的协议,可以实现自己的ReqestInfo,把数据包内容直接装入帧对象。

    SuperSocket 层次示意图

    SuperSocket层次解析:

    1. 设备层:基于flash和SilverLight的策略服务器和基于接收过滤器的协议实施。
    2. 应用层:可扩展的应用程序服务:包括多种API集成。会话容器和命令框架。
    3. 套接字层: 通过传输协议TCP和UDP的事件驱动套接字服务。

    SuperSocket 请求处理模型示意图

    模型解析:

    1. 客户端携带数据流与Server端Socket Listener建立连接之后,SuperSocket 服务就将这一个连接视为一个Session会话。表示客户端和服务器端的一个逻辑连接,数据的收发都是在这个Session中进行处理的(此过程中的数据流为二进制数据)。
    2. 携带数据流的Session通过默认或者自定的接受过滤器将过滤后的数据传递到RequestInfo对象。每一个客户端对象都得实例化一个RequestInfo类,将接收到的二进制流转换成请求的实例。
    3. 根据RequestInfo执行Command命令,一个Command 包含一个Session和RequestInfo,在Command中根据需求解析数据。也可通过Session向客户端发送数据,例如有些DTU或者RTU设备需要发送指令才能返回数据。

     SuperSocket 对象模型图示意图

    模型解析:

    1. 应用服务AppServer 包括命令Commands, 会话容器Session contaioner。
    2. 对象层次:基本配置Config->命令过滤器Command Filters->日志和日志工厂Log/LogFactory->命令装载机CommandLoaders->接收过滤器工厂ReceiveFilterFactory->连接过滤Connection Filters。
    3. Socket 服务:多客户端监听,TCP1 、TCP2、。。。。UDP。

    4、SuperSocket内置的常用协议实现模版

    为了减少码农的工作量,SuperSocket内置的常用协议实现模版如下:

    • TerminatorReceiveFilter ,结束符协议(SuperSocket.SocketBase.Protocol.TerminatorReceiveFilter, SuperSocket.SocketBase)
    • CountSpliterReceiveFilter ,固定数量分隔符协议(SuperSocket.Facility.Protocol.CountSpliterReceiveFilter, SuperSocket.Facility)
    • FixedSizeReceiveFilter, 固定请求大小的协议 (SuperSocket.Facility.Protocol.FixedSizeReceiveFilter, SuperSocket.Facility)
    • BeginEndMarkReceiveFilter,带起止符的协议 (SuperSocket.Facility.Protocol.BeginEndMarkReceiveFilter, SuperSocket.Facility)
    • FixedHeaderReceiveFilter ,头部格式固定并且包含内容长度的协议(SuperSocket.Facility.Protocol.FixedHeaderReceiveFilter, SuperSocket.Facility)

    以上模板的使用可参考官方文档http://docs.supersocket.net/v1-6/zh-CN/The-Built-in-Common-Format-Protocol-Implementation-Templates

    5、通过请求处理模型可以总结基本的开发流程

    1. 实例化AppServer对象,时刻监听客户端的会话。
    2. 定义RequestInfo实体类型,接收和处理二进制字符流。
    3. 定义数据接收过滤器,ReceiveFilter,接收过滤后的数据,并将数据赋值给RequestInfo实体类型。
    4. 在appServer的构造函数中继承使用接收过滤工厂RequestFilterFactory,并执行自定的ReceiveFilter和RequestInfo。
    5. 在1的数据请求委托事件中解析并使用RequestInfo实体中对应的数据。

    二、通过FixedHeaderReceiveFilter解析自定义协议

    自定义自己服务器中相关的类,建议类的建立顺序:RequestInfo>ReceiveFilter>AppSession>AppServer

    通信协议格式如下:

    image

    在FixedHeaderReceiveFilter,头部指数据内容之前的数据(即数据长度L之前的部分),以上协议可以知道,头部包含11个字节.

    1、自定义请求类型RequestInfo

    先实现一个客户端请求的实体类RequestInfo,该RequestInfo类必须实现接口 IRequestInfo,该接口只有一个名为"Key"的字符串类型的属性。
    SuperSocket设计了两个RequestInfo类:StringRequestInfo 和BinaryRequestInfo,这里我们自定义一个来GDProtocolRequestInfo实现:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using SuperSocket.SocketBase.Protocol;
    
    namespace GDServer
    {
    
        public class GDProtocolRequestInfo : IRequestInfo
        {
            /// <summary>
            /// [不使用]
            /// </summary>
            public string Key { get; set; }
    
            /// <summary>
            /// 设备逻辑地址
            /// </summary>
            public string DeviceLogicalCode { get; set; }
    
            /// <summary>
            /// 命令序列号
            /// </summary>
            public string Seq { get; set; }
    
            /// <summary>
            /// 控制码
            /// </summary>
            public string ControlCode { get; set; }
    
            /// <summary>
            /// 数据长度
            /// </summary>
            public string Length { get; set; }
    
            /// <summary>
            /// 数据域
            /// </summary>
            public string Data { get; set; }
    
            /// <summary>
            /// CS校验
            /// </summary>
            public string Cs { get; set; }
    
            /// <summary>
            /// 当前完整帧
            /// </summary>
            //public string EntireFrame { get; set; }
        }
    }

    2、自定义接收过滤器ReceiveFilter

    设计基于类FixedHeaderReceiveFilter实现自己的接收过滤器GDProtocolReceiveFilterV2,主要实现GetBodyLengthFromHeader和ResolveRequestInfo方法,实现如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using SuperSocket.SocketBase.Protocol;
    using SuperSocket.Facility.Protocol;//
    using SuperSocket.Common;//
    
    namespace GDServer
    {
        /// <summary>
        /// 广东规约过滤器V2,(帧格式为GDProtocolRequestInfo)
        /// </summary>
        public class GDProtocolReceiveFilterV2 : FixedHeaderReceiveFilter<GDProtocolRequestInfo>
        {
            public GDProtocolReceiveFilterV2()
                : base(11)
            {
    
            }
    
            /// <summary>
            /// 获取数据域和结尾字节长度
            /// </summary>
            /// <param name="header"></param>
            /// <param name="offset"></param>
            /// <param name="length"></param>
            /// <returns></returns>
            protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
            {
                //length为头部(包含两字节的length)长度
    
                //获取高位
                byte high = header[offset + length - 1];
                //获取低位
                byte low = header[offset + length - 2];
                int len = (int)high * 256 + low;
                return len + 2;//结尾有2个字节
            }
    
            /// <summary>
            /// 实现帧内容解析
            /// </summary>
            /// <param name="header"></param>
            /// <param name="bodyBuffer"></param>
            /// <param name="offset"></param>
            /// <param name="length"></param>
            /// <returns></returns>
            protected override GDProtocolRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
            {
                GDProtocolRequestInfo res = new GDProtocolRequestInfo();
                string entireFrame = BytesToHexStr(header.Array) + BytesToHexStr(bodyBuffer.CloneRange(offset, length));
                //res.EntireFrame = entireFrame;
                res.DeviceLogicalCode = entireFrame.Substring(2, 8);
                res.Seq = entireFrame.Substring(10, 4);
                res.ControlCode = entireFrame.Substring(16, 2);
                res.Length = entireFrame.Substring(18, 4);
                int dataLen = int.Parse(HEXtoDEC(ReverseHexString(res.Length)));
                res.Data = entireFrame.Substring(22, dataLen * 2);
                res.Cs = entireFrame.Substring(22 + dataLen * 2, 2);
                return res;
            }
    
            /// <summary>
            /// 高低对调
            /// </summary>
            /// <param name="str"></param>
            /// <returns></returns>
            string ReverseHexString(string str)
            {
                char[] buff = new char[str.Length];
                for (int i = 0; i < str.Length; i += 2)
                {
                    buff[i] = str[str.Length - i - 2];
                    buff[i + 1] = str[str.Length - 1 - i];
                }
                string s = new string(buff);
                return s;
            }
    
            /// <summary>
            /// 16进制转10进制
            /// </summary>
            /// <param name="HEX"></param>
            /// <returns></returns>
            string HEXtoDEC(string HEX)
            {
                return Convert.ToInt64(HEX, 16).ToString();
            }
    
            /// <summary>
            /// 转化bytes成16进制的字符
            /// </summary>
            /// <param name="bytes"></param>
            /// <returns></returns>
            string BytesToHexStr(byte[] bytes)
            {
                string returnStr = "";
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                    }
                }
                return returnStr;
            }
        }
    }

    3、自定义的AppSession

    先创建新的AppSession,GDProtocolSessionV2,新的AppServer将使用它。

    using SuperSocket.SocketBase;
    using SuperSocket.SocketBase.Protocol;
    using System;
    
    namespace GDServer
    {
        public class GDProtocolSessionV2 : AppSession<GDProtocolSessionV2, GDProtocolRequestInfo>
        {
            protected override void HandleException(Exception e)
            {
    
            }
        }
    }

    4、自定义AppServer

    使用该协议的方法是使用接收或者自己定义的接收过滤器工厂来在 SuperSocket 中启用该协议

    using SuperSocket.SocketBase;
    using SuperSocket.SocketBase.Protocol;
    
    namespace GDServer
    {
        public class GDProtocolServerV2 : AppServer<GDProtocolSessionV2, GDProtocolRequestInfo>
        {
            public GDProtocolServerV2()
                : base(new DefaultReceiveFilterFactory<GDProtocolReceiveFilterV2, GDProtocolRequestInfo>()) //使用默认的接受过滤器工厂 (DefaultReceiveFilterFactory)
            {
            }
        }
    }

    5、测试程序

    这样,GDProtocolServerV2就完成了,下面是测试代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using GDServer;
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                var gdServer = new GDProtocolServerV2();
                gdServer.Setup(2015);
                gdServer.NewSessionConnected += gdServer_NewSessionConnected;
                gdServer.NewRequestReceived += gdServer_NewRequestReceived;
                gdServer.SessionClosed += gdServer_SessionClosed;
                gdServer.Start();
                Console.WriteLine("server is:" + gdServer.State.ToString());
                while (true)
                {
                    if (Console.ReadKey().KeyChar == 'q')
                    {
                        gdServer.Stop();
                        gdServer.Dispose();
                        return;
                    }
                }
            }
    
            static void gdServer_SessionClosed(GDProtocolSessionV2 session, SuperSocket.SocketBase.CloseReason value)
            {
                Console.WriteLine(session.RemoteEndPoint.ToString() + " closed. reason:" + value);
            }
    
            static void gdServer_NewRequestReceived(GDProtocolSessionV2 session, GDProtocolRequestInfo requestInfo)
            {
                var info = requestInfo;
                Console.WriteLine("receive from: " + session.RemoteEndPoint.ToString());
                Console.WriteLine("DeviceLogicalCode:" + info.DeviceLogicalCode);
                Console.WriteLine("Seq:" + info.Seq);
                Console.WriteLine("ControlCode:" + info.ControlCode);
                Console.WriteLine("Length:" + info.Length);
                Console.WriteLine("Data:" + info.Data);
                Console.WriteLine("Cs:" + info.Cs);
                Console.WriteLine("-------------------------------------------------------------");
            }
    
            static void gdServer_NewSessionConnected(GDProtocolSessionV2 session)
            {
                Console.WriteLine(session.RemoteEndPoint.ToString() + " connected.");
            }
        }
    }

    测试结果:

    分别发送符合该协议格式的帧(用TCP调试助手使用hex方式发送)

    68 77 77 12 34 00 01 68 A1 03 00 11 11 11 DC 16

    68 77 77 12 34 41 01 68 01 0C 00 01 00 00 00 00 00 00 00 30 80 10 80 94 16

    68 77 77 12 34 41 01 68 88 08 00 00 00 30 80 00 10 80 00 16 16

    68 77 77 12 34 41 01 68 95 23 00 00 0B 00 00 10 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 5B 00 00 00 00 00 00 00 00 00 00 00 00 00 32 9E 16

    打印结果如下:

    server is:Running
    127.0.0.1:34360 connected.
    receive from: 127.0.0.1:34360
    DeviceLogicalCode:77771234
    Seq:0001
    ControlCode:A1
    Length:0300
    Data:111111
    Cs:DC
    -------------------------------------------------------------
    receive from: 127.0.0.1:34360
    DeviceLogicalCode:77771234
    Seq:4101
    ControlCode:01
    Length:0C00
    Data:010000000000000030801080
    Cs:94
    -------------------------------------------------------------
    receive from: 127.0.0.1:34360
    DeviceLogicalCode:77771234
    Seq:4101
    ControlCode:88
    Length:0800
    Data:0000308000108000
    Cs:16
    -------------------------------------------------------------
    receive from: 127.0.0.1:34360
    DeviceLogicalCode:77771234
    Seq:4101
    ControlCode:95
    Length:2300
    Data:000B0000100000000000FFFFFFFFFFFFFFFF00005B0000000000000000000000000032
    Cs:9E
    -------------------------------------------------------------

    以上代码请自行引入SuperSocket的dll和System.configuration.dll

    本文由http://www.cnblogs.com/xiepeixing/原创,转载请著名出处

    三 、SuperSocket 1.6 中文文档

    http://docs.supersocket.net/v1-6/zh-CN

    四、入门教程

    https://www.cnblogs.com/fly-bird/category/938912.html

    五、入门实例下载

    链接:https://pan.baidu.com/s/1-Q0a4wsNcwyJI7_D0sbsXw 密码:zda7

  • 相关阅读:
    PHP使用数据库永久连接方式操作MySQL的是与非
    php生成xml文件
    Ruby学习之类
    新增题目功能模块总结
    Ruby学习之类2
    smarty section循环成两列的问题
    jQuery validate插件初探
    Zend Framework学习之Zend_Config
    Zend Framework学习之Zend_Loader动态加载文件和类
    JS 删除字符串最后一个字符的方法
  • 原文地址:https://www.cnblogs.com/springsnow/p/9544285.html
Copyright © 2011-2022 走看看