zoukankan      html  css  js  c++  java
  • 我的第一个Socket程序-SuperSocket使用入门(一)

    第一次使用Socket,遇到过坑,也涨过姿势,网上关于SuperSocket的教程基本都停留在官方给的简单demo上,实际使用还是会碰到一些问题,所以准备写两篇博客,分别来介绍SuperSocket以及实际的案例应用,应用中我还遇到一些问题,还没解决,还请有经验的指出问题

    --------------------------------------------------------------------------------begin-------------------------------------------------------------------------------

    先奉上官方网址:http://www.supersocket.net/  源码:http://supersocket.codeplex.com/releases/view/161987

    官方的源码目前就不推荐看了,毕竟也是新手,不一定看得懂,使用前先看下官方的文档:http://docs.supersocket.net/  官方源码目录中有个QuickStart文件夹,顾名思义就是快速开始,官方的Demo,这里很想吐槽,网上的很多Demo都是官方Demo都是这个源码中最简单的那个,操,那有个毛用!这一篇就不扯其他的了,只讲SuperSocket的使用

    本人书读的比较少,文笔比较差,所以我尽量来写清楚SuperSocket的使用逻辑

    一个SuperSocket的程序,可以包含多个Socket服务(称为AppServer),一个Socket服务中有多个客户端连接对象(称这个连接对象为AppSession),一个客户端与Socket服务通讯命令都在AppSession中进行(称这个命令为Commands),每一个命令在被执行前我们可以来控制这个命令是否给予执行,类似与MVC中的 Action Filter(称为CommandFilterAttribute),还有一些其他的例如命令行协议的,用默认的就可以了,复杂的Socket程序可能需要自定义协议,这里我们不予深究(其实也简单,搞懂上面的,这个就好搞了)

    接下来我拿我项目的代码分别对上面列出的概念来说明

    我用的是最新的SuperSocket1.6.4.0,VS2013,需要使用三个官方提供的类库:SuperSocket.Common.dll,SuperSocket.SocketBase.dll,SuperSocket.SocketEngine.dll,上面忘了说了,SuperSocket集成了日志插件:log4net,所以这里我们也要引用,注意这个1.6.4.0对应的log4net版本为:1.2.13.0,一定要使用官方Demo包中的dll,避免版本引用不一致的问题,项目结构(控制台程序):

    结构实际是参照官方的,如图:,对应文件夹为:

    这是一个将Socket程序的宿主使用Windows服务的形式运行,为什么要使用WindowsService就不解释了,后面再会写篇来介绍使用服务。我曾建个普通的windows服务项目,把SuperSocket的代码集成进去,无奈服务启动就特么停止,不清楚为啥,所以使用官方提供的Demo,官方的代码我就不解释了(其实是我也没看懂...),我们要通过配置文件来启动Socket程序,所以先看下App.config

    <configuration>
      <configSections>
        <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/><!-- 注册log4net -->
        <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/><!-- 注册SuperSocket -->
      </configSections>
      <appSettings>
        <add key="ServiceName" value="SupperSocketService"/>  <!-- 服务名称 -->
        <add key="ServiceDescription" value="试镜成Socket程序"/>  <!-- 服务说明 -->
      </appSettings>
      <superSocket>
        <servers>
          <server name="WeChatSocket" textEncoding="gb2312" serverType="LXGlass.SocketService.WeChatServer, LXGlass.SocketService" ip="Any" port="2020" maxConnectionNumber="100">
          </server> <!-- 一个socket服务(AppServer),当然可以配置多个 -->
        </servers>
      </superSocket>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
      </startup>
      <runtime>
        <gcServer enabled="true" />
      </runtime>
    </configuration>

    上面说了,每个命令都在AppSession中,所以先来建个AppSession:

    /// <summary>
        /// 微信Session
        /// </summary>
        public class WeChatSession:AppSession<WeChatSession>
        {
    
            /// <summary>
            /// 是否登录
            /// </summary>
            public bool isLogin { get; set; }
    
            /// <summary>
            /// 机器编码
            /// </summary>
            public string SN { get; set; }
                
    
            protected override void OnSessionStarted()
            {
                //this.Send("Welcome to SuperSocket WeChat Server
    ");
            }
    
            protected override void OnInit()
            {
                //this.Charset = Encoding.GetEncoding("gb2312");
                base.OnInit();
            }
    
            protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
            {
                LogHelper.WriteLog("收到命令:" + requestInfo.Key.ToString());
                this.Send("不知道如何处理 " + requestInfo.Key.ToString() +" 命令
    ");
            }
    
    
            /// <summary>
            /// 异常捕捉
            /// </summary>
            /// <param name="e"></param>
            protected override void HandleException(Exception e)
            {
                this.Send("
    
    异常信息:{0}", e.Message);
                //base.HandleException(e);
            }
    
            /// <summary>
            /// 连接关闭
            /// </summary>
            /// <param name="reason"></param>
            protected override void OnSessionClosed(CloseReason reason)
            {
                base.OnSessionClosed(reason);
                  
            }
        }

    在这个Session中我额外定义了两个属性:isLogin、SN,Session也就类似与asp.net中的Session

    接着把AppSession注册到服务(AppServer)中

    /// <summary>
        /// 微信服务
        /// </summary>
        //[WeChatCheckCommandFilter]
        public  class WeChatServer:AppServer<WeChatSession>
        {
    
            protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
            {
                return base.Setup(rootConfig, config);
            }
    
            protected override void OnStarted()
            {
                LogHelper.WriteLog("WeChat服务启动");
                base.OnStarted();
    
            }
    
            protected override void OnStopped()
            {
                LogHelper.WriteLog("WeChat服务停止");
                base.OnStopped();
            }
    
            /// <summary>
            /// 新的连接
            /// </summary>
            /// <param name="session"></param>
            protected override void OnNewSessionConnected(WeChatSession session)
            {
                //LogHelper.WriteLog("WeChat服务新加入的连接:" + session.LocalEndPoint.Address.ToString());
                base.OnNewSessionConnected(session);
            }
    
        }
    

     注意这两个类的继承关系,代码很简单,我把我的业务代码删掉了,先搞懂supersocket

    再接着就是关键了(其实这些都是关键....),命令!先建一个CHECK的命令:

    public class CHECK : CommandBase<WeChatSession, StringRequestInfo>
        {
            public override void ExecuteCommand(WeChatSession session, StringRequestInfo requestInfo)
            {
                if (requestInfo.Parameters.Count() != 1)
                {
                    session.Send("The wrong format
    ");
                }
                else
                {
                    string sn = requestInfo.Parameters[0].ToString();
                    if (string.IsNullOrWhiteSpace(sn))
                        session.Send("The wrong sn
    ");
                    else
                    {
                        //已用此SN注册的连接会替换Sesion
                        var session_client = session.AppServer.GetAllSessions().Where(c => c.SN == sn);
                        if (session_client != null)
                        {
                            foreach (var item in session_client)
                            {
                                item.Send("new check,To close the connection for you
    ");
                                item.Close();
                            }
                        }
    
                        session.isLogin = true;
                        session.SN = sn;
                        session.Send("success
    ");
                    }
                }
            }
        }

    这个命令继承自:CommandBase<WeChatSession, StringRequestInfo>,WeChatSession为我们刚才写的Session,StringRequestInfo为当前请求命令中的信息

    当客户端发送:CHECK 1 就会收到success的返回,关于这个格式,就是命令行协议了,我这里使用默认的,想要自定义,去参照官方文档,这个默认的命令行协议的规则:每次请求和响应的数据结尾都有 也就是换行符,通过 来判断命令的结尾,CHECK为命令key,requestInfo.Key可以获得,上面的requestInfo.Parameters[0]是这个key后面以空格进行分割得到数组,所以requestInfo.Parameters[0]就可以取到CHECK 1 中的1,需要更多的数据就继续空格加

    我代码中有段:已用此SN注册的连接会替换Sesion这里解释一下,因为每连上一个客户端,我们都要给他一个标识(这也是CHECK命令存在的意义),当一个客户端已用这个CHECK 1注册了,另外一个客户端也要用CHECK 1来注册,那程序就有两个sn=1的session了,为了保证唯一性,所以这里要把之前已注册CHECK=1的给踢掉,请无视item.send中的英文

    需要其他命令的再添加类,继承CommandBase<WeChatSession, StringRequestInfo>

    推荐个Socket客户端调试工具:SocketTool,下载地址:http://pan.baidu.com/s/1dDcZCfJ

    基础就到这里了,下一篇说说实际的应用

  • 相关阅读:
    hdu1828(线段树——矩形周长并)
    hdu1255(线段树——矩形面积交)
    用jQuery获取到一个类名获取到的是一个数组 ,如果对数组中的每个进行相应的操作可以这样进行
    CSS3向外扩散的圆
    鼠标放上去图片会放大
    Django分页
    Django使用富文本编辑器
    Django日志配置
    Linux中的文件类型
    Linux压缩和解压缩
  • 原文地址:https://www.cnblogs.com/New-world/p/4511543.html
Copyright © 2011-2022 走看看