C# SuperSocket 手把手教你入门 傻瓜教程---5(探索自定义AppServer、AppSession,Conmmand,用配置文件App.comfig启动服务器)

36 篇文章 44 订阅

 C# SuperSocket 手把手教你入门 傻瓜教程系列教程

C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据)

C# SuperSocket 手把手教你入门 傻瓜教程---2(服务器和客户端双向通信)

C# SuperSocket 手把手教你入门 傻瓜教程---3(Telnet服务器和客户端请求处理)

C# SuperSocket 手把手教你入门 傻瓜教程---4(创建一个服务器和多客户端双向通信程序)

 C# SuperSocket 手把手教你入门 傻瓜教程---5(探索自定义AppServer、AppSession,Conmmand,用配置文件App.comfig启动服务器)

C# SuperSocket 手把手教你入门 傻瓜教程---6(CommandLineProtocol---命令行协议)

C# SuperSocket 手把手教你入门 傻瓜教程---7(自定义CommandLineProtocol---命令行协议)

C# SuperSocket 手把手教你入门 傻瓜教程-8(TerminatorReceiveFilter - 结束符协议) 

目录

一、为什么要使用自定义类AppServer、AppSession,Conmmand

二、为什么要通过配置文件App.comfig启动服务器

三、创建工程项目

四、下载SuperSocket动态库

1、安装SuperSocket组件

2、安装SuperSocket.Engine组件

3、log4net.config的【复制到输出目录】组态为“如果较新则复制”

五、自定义AppSession类

1、工程项目中添加一个自定义类SocketSession类

2、SocketSession类完整的代码如下:

六、自定义AppServer类

1、工程项目中添加一个自定义类SocketServer

2、SocketServer类完整的代码如下:

七、使用Command

(一)、定义一个名为"Hello "的类去处理Key为"Hello"的请求。

(二)、定义一个名为"ADD"的类去处理Key为"ADD"的请求:

(三)、定义一个名为"MULT"的类去处理Key为"MULT"的请求:

(四)、定义一个名为"Echo"的类去处理Key为"Echo"的请求:

八、program.cs

九、配置App.config使用BootStrap启动SuperSocket

1、SuperSocket配置section 。

2、Server实例的配置     

十、完整的工程项目

十一、验证

十二、源程序

十三、致谢


        在前几篇文章中,我们已经了解到了如何在SuperSocket处理客户端请求。之前我们借助SuperSocket实现了一个简易版的服务器,但是不管是Server还是Session都是使用SuperSocket框架提供的Server和Session(即框架内置的Server类和Session类)。

一、为什么要使用自定义类AppServer、AppSession,Conmmand

        我们可能会发现一个问题,如果我们的服务器端包含有很多复杂的业务逻辑,这样的话如果仍然SuperSocket框架提供的内置的Server类和Session类,在编程时使用switch/case代码将会很长而且非常难看,并且没有遵循面向对象设计的原则(OOD)。

        因此本篇博客我们要实现自己定义的Server类和Session类,来重写SuperSocket​​​​​​​框架原生的Server类或Session类的方法,通过添加自己所需的属性,来实现自己的业务逻辑,并且也不在使用事件来绑定接收,连接,或关闭事件全部交给Bootstrap来执行,(这个Bootstrap并不是指前端框架的Bootstrap,而是指的SuperSocket框架的一个引导程序或说是辅助程序),就是这里我们使用Bootstrap 来配置启动SuperSocket服务器程序。

二、为什么要通过配置文件App.comfig启动服务器

  1. 避免硬编码
  2. SuperSocket提供了很多有用的配置选项
  3. 可以充分利用SuperSocket提供的工具

        前面几篇文章,我们都使用如下方法启动服务器

            var appServer = new AppServer();

            if (!appServer.Setup(2017)) // Setup with listening port
            {
                Console.WriteLine("Failed to Setup!");
                Console.ReadKey();
                return;
            }

         有没有更好的方法,不需要修改任何源程序就可以完成服务器的启动呢?答案就是使用APP.config配置文件启动服务器我们可以在配置文件中方便的修改服务器的端口号和IP地址,而不需要修改源程序。

         下面我们就创建自定义AppSession类,自定义AppServer类,自定义Command类以及通过APP.config配置文件启动服务器。

三、创建工程项目

        创建控制台项目:打开visual Studio 2017程序,文件--->新建--->项目

        创建一个项目名称为:SuperSocketClass 的工程项目。

         SuperSocketClass就是APP.config配置文件中的实例名称

四、下载SuperSocket动态库

        最好通过Visual Stuido 2017程序的NuGet来获取,本人也比较喜欢这种方式,可以更新组件版本。

 1、安装SuperSocket组件

点击浏览,输入SuperSocket,选中SuperSocket组件安装SuperSocket组件。

2、安装SuperSocket.Engine组件

 

3、log4net.config的【复制到输出目录】组态为“如果较新则复制”

添加完成组件后需要注意将config文件进行编译成内容,log4net需要使用config文件

将Config文件夹中的log4net.config的【复制到输出目录】组态为“如果较新则复制”

4、查看引入后的项目整体目录,框红线的为引入supersocket组件和log4net文件 

五、自定义AppSession类

        AppSession 代表一个和客户端的逻辑连接,基于连接的操作应该放在该类之中。你可以用该类的实例发送数据到客户端,接收客户端发送的数据或者关闭连接。

     使用方法:创建自定义类SocketSession,继承AppSession类并重写AppSession类的方法(注意:一个AppSession对象对应一个连接)

1、工程项目中添加一个自定义类SocketSession类

2、SocketSession类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketEngine;



namespace SuperSocketClass.Config
{
    /// <summary>  
    /// 自定义连接类SocketSession,继承AppSession,并传入到AppSession  
    /// </summary>  
    public class SocketSession : AppSession<SocketSession>
    {
        public override void Send(string message)
        {
            Console.WriteLine("发送消息:" + message);
            base.Send(message);
        }


        protected override void OnSessionStarted()
        {
            //输出客户端IP地址  
            Console.WriteLine(this.LocalEndPoint.Address.ToString());
            this.Send("Hello User,Welcome to SuperSocket Telnet Server!");
        }


        /// <summary>  
        /// 连接关闭  
        /// </summary>  
        /// <param name="reason"></param>  
        protected override void OnSessionClosed(CloseReason reason)
        {
            base.OnSessionClosed(reason);
        }


        protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
        {
            Console.WriteLine($"遇到未知的请求 Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
            base.HandleUnknownRequest(requestInfo);
        }

        /// <summary>  
        /// 捕捉异常并输出  
        /// </summary>  
        /// <param name="e"></param>  
        protected override void HandleException(Exception e)
        {
            this.Send("error: {0}", e.Message);
        }
    }
}

六、自定义AppServer类

        AppServer 代表了监听客户端连接,承载TCP连接的服务器实例。理想情况下,我们可以通过AppServer实例获取任何你想要的客户端连接,服务器级别的操作和逻辑应该定义在此类之中。

        使用方法:创建自定义类SocketServer,继承AppServer类并重写AppServer类的方法

1、工程项目中添加一个自定义类SocketServer

2、SocketServer类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;



using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketEngine;


namespace SuperSocketClass.Config
{

    public class SocketServer : AppServer<SocketSession>
    {
        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            Console.WriteLine("正在准备配置文件");
            return base.Setup(rootConfig, config);
        }

        protected override void OnStarted()
        {
            Console.WriteLine("服务已开始");
            base.OnStarted();
        }

        protected override void OnStopped()
        {
            Console.WriteLine("服务已停止");
            base.OnStopped();
        }


        /// <summary>  
        /// 输出新连接信息  
        /// </summary>  
        /// <param name="session"></param>  
        protected override void OnNewSessionConnected(SocketSession session)
        {
            base.OnNewSessionConnected(session);
            //输出客户端IP地址  
            Console.Write("\r\n" + session.LocalEndPoint.Address.ToString() + ":连接");
        }


        /// <summary>  
        /// 输出断开连接信息  
        /// </summary>  
        /// <param name="session"></param>  
        /// <param name="reason"></param>  
        protected override void OnSessionClosed(SocketSession session, CloseReason reason)
        {
            base.OnSessionClosed(session, reason);
            Console.Write("\r\n" + session.LocalEndPoint.Address.ToString() + ":断开连接");
        }
    }
}

        警告: 自定义类SocketServer创建在Config文件夹下,因此【实例运行的AppServer类型】完整的路径是: 

SuperSocketClass.Config.SocketServer

         下图中SuperSocketClass.Config.SocketServer就是APP.config配置文件中的实例运行的AppServer类型的完整路径。

七、使用Command

         在SuperSocket中的Command让我们进行扩展,使用方法也极其简单。只需要继承一个CommandBase<AppSession, StringRequestInfo>类。(注意:如果使用了自定义的Session需要修改此处,如ADD类下的ADD:CommandBase<SocketSession, StringRequestInfo>)类),并override这个类ExecuteCommand方法

          同时我们要移除请求处理方法的注册,因为它和命令不能同时被支持,注释下面代码即可

    //appServer.NewRequestReceived += new RequestHandler<SocketSession, StringRequestInfo>(appServer_NewRequestReceived);

        现在我们来修改C# SuperSocket 手把手教你入门 傻瓜教程---3(Telnet服务器和客户端请求处理)这篇文章中的示例,先取消Telnet示例中的 appServer.NewRequestReceived 事件处理。这样我们就可以编写大量的命令让我们的Socket更灵活。

        例如,我们可以定义一个名为"Hello "的类去处理Key为"Hello"的请求。

                                 定义一个名为"ADD"的类去处理Key为"ADD"的请求:

                                 定义一个名为"MULT"的类去处理Key为"MULT"的请求:

                                 定义一个名为"Echo"的类去处理Key为"Echo"的请求:

(一)、定义一个名为"Hello "的类去处理Key为"Hello"的请求。

1、工程项目中添加一个自定义类Hello

  2、Hello类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;



using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Command;



namespace SuperSocketClass.Config
{
    public class Hello : CommandBase<SocketSession, StringRequestInfo>
    {
        /// <summary>  
        /// 自定义执行命令方法,注意传入的变量session类型为MySession  
        /// </summary>  
        /// <param name="session">会话</param>  
        /// <param name="requestInfo">请求数据信息</param>  
        public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
        {
            session.Send(string.Format("Hello {0}:{1}   {2}", session.Config.Ip, session.Config.Port, requestInfo.Body));
        }
    }
}

(二)、定义一个名为"ADD"的类去处理Key为"ADD"的请求:

1、工程项目中添加一个自定义类ADD

   2、ADD类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;



using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Command;



namespace SuperSocketClass.Config
{
    public class ADD : CommandBase<SocketSession, StringRequestInfo>
    {
        public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
        {
            session.Send(requestInfo.Parameters.Select(p => Convert.ToInt32(p)).Sum().ToString());
        }

    }
}

(三)、定义一个名为"MULT"的类去处理Key为"MULT"的请求:

1、工程项目中添加一个自定义类MULT

    2、MULT类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Command;



namespace SuperSocketClass.Config
{
    public class MULT : CommandBase<SocketSession, StringRequestInfo>
    {
        public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
        {
            var result = 1;

            foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p)))
            {
                result *= factor;
            }

            session.Send(result.ToString());
        }
    }
}

(四)、定义一个名为"Echo"的类去处理Key为"Echo"的请求:

1、工程项目中添加一个自定义类Echo

     2、Echo类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Command;



namespace SuperSocketClass.Config
{
    public class Echo : CommandBase<SocketSession, StringRequestInfo>
    {
        public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
        {
            session.Send(requestInfo.Body);
        }

    }
}

八、program.cs

        需要修改program.cs。

        将原有【C# SuperSocket 手把手教你入门 傻瓜教程---3(Telnet服务器和客户端请求处理)】program.cs中定义的端口信息以及方法注释掉,只保留服务器启动和停止的代码。然后引入using SuperSocket.SocketEngine;     使用BootStrap启动服务器。

        在program.cs类中先要删除原先启动服务器方式的代码,然后改为使用App.config文件配置,用BootStrap启动服务器。

        警告:要想使用BootStrap启动服务器,必须引用

using SuperSocket.SocketEngine;

     1、program类完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketEngine;



/****************************************************************
*   作者:霸王猫
*   创建时间:2022-01-19 00:02:17
*   2022
*   描述说明:自定义连接类SocketSession,继承AppSession,并传入到AppSession  
*****************************************************************/


namespace SuperSocketClass
{
    class Program
    {
        /// <summary>
        /// SuperSocket服务启动或停止
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //var appServer = new AppServer();
            //启动应用服务端口
            //if (!appServer.Setup(2017)) //启动时监听端口2017
            //{
            //Console.WriteLine("服务端口启动失败!");
            //Console.ReadKey();
            //return;
            //}

            //Console.WriteLine();

            //尝试启动应用服务
            //if (!appServer.Start())
            //{
            //Console.WriteLine("服务启动失败!");
            //Console.ReadKey();
            //return;
            //}

            //Console.WriteLine("服务启动成功,请按'q'停止服务!");

            //appServer.NewSessionConnected += appServer_NewSessionConnected;
            //appServer.NewRequestReceived += appServer_NewRequestReceived;


            //while (Console.ReadKey().KeyChar != 'q')
            //{
            //Console.WriteLine();
            //continue;
            //}

            //停止服务
            //appServer.Stop();

            //Console.WriteLine("服务已停止!");
            //Console.ReadKey();

            // }

            //static void appServer_NewSessionConnected(AppSession session)
            //{
            //session.Send("Welcome to SuperSocket Telnet Server!");
            //}


            /// <summary>
            ///客户端请求处理
            /// </summary>
            /// <param name="session">会话</param>
            /// <param name="requestInfo">请求信息</param>

            //static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
            //{
            //switch (requestInfo.Key.ToUpper())
            //{
            //  case ("ECHO"):
            //session.Send(requestInfo.Body);
            //break;

            //   case ("ADD"):
            //session.Send(requestInfo.Parameters.Select(p => Convert.ToInt32(p)).Sum().ToString());
            //break;

            //    case ("MULT"):

            //var result = 1;

            //foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p)))
            //{
            //result *= factor;
            //}

            //session.Send(result.ToString());
            //break;
            //}



                Console.WriteLine("请按任何键进行启动SuperSocket服务!");
                Console.ReadKey();
                Console.WriteLine();
                var bootstrap = BootstrapFactory.CreateBootstrap();

                if (!bootstrap.Initialize())
                {
                    Console.WriteLine("初始化失败!");
                    Console.ReadKey();
                    return;
                }

                var result = bootstrap.Start();

                Console.WriteLine("服务正在启动: {0}!", result);

                if (result == StartResult.Failed)
                {
                    Console.WriteLine("服务启动失败!");
                    Console.ReadKey();
                    return;
                }
                Console.WriteLine("服务启动成功,请按'q'停止服务!");

                while (Console.ReadKey().KeyChar != 'q')
                {
                    Console.WriteLine();
                    continue;
                }

                //停止服务
                // appServer.Stop();
                bootstrap.Stop();
                Console.WriteLine("服务已停止!");
                Console.ReadKey();


            }
        }

}

九、配置App.config使用BootStrap启动SuperSocket

1、SuperSocket配置section 。

        SuperSocket使用.NET自带的配置技术,SuperSocket有一个专门的配置Section,使用配置启动SuperSocket可以灵活配置选项。

 <configSections>
    <!--log 日志记录-->
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
    <!--SocketEngine-->
    <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
  </configSections>

2、Server实例的配置     

  <!--SuperSocket服务配置信息 serverType是项目的服务如我自定义的Socketserver-->
  <!--name: 实例名称
      serverType: 实例运行的AppServer类型
      ip: 侦听ip
      port: 侦听端口-->
  <superSocket>
    <servers>
      <!--textEncoding 编码方式"gb2312","utf-8" 默认是acii-->
      <server name="SuperSocketClass" 
       textEncoding="gb2312" 
       serverType="SuperSocketClass.Config.SocketServer,SuperSocketClass"
       ip="Any"
       port="2017"
       maxConnectionNumber="100">
      </server>
    </servers>
  </superSocket>

         这里解释一下配置的服务器节点:

name: 实例名称(就是:工程项目的解决方案名称:SuperSocketClass

serverType: 实例运行的AppServer类型(就是之前我们创建的自定义AppServer类SocketServer】,它创建在Config文件夹下,因此它的全称为SuperSocketClass.Config.SocketServer

ip: 侦听ip

port: 侦听端口

name: 实例名称                                          --->   SuperSocketClass
serverType: 实例运行的AppServer类型     --->  SuperSocketClass.Config.SocketServer
ip: 侦听ip                                                     --->  Any
port: 侦听端口                                             ---> 2017

完整的App.config配置文件如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <!--log 日志记录-->
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
    <!--SocketEngine-->
    <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
  </configSections>


  <!--服务信息描述,在window服务模式下的名称标识-->
  <appSettings>
    <add key="ServiceName" value="SupperSocketClass"/>
    <add key="ServiceDescription" value="霸王猫"/>
  </appSettings>


  <!--SuperSocket服务配置信息 serverType是项目的服务如我自定义的Socketserver-->
  <!--name: 实例名称
      serverType: 实例运行的AppServer类型
      ip: 侦听ip
      port: 侦听端口-->
  <superSocket>
    <servers>
      <!--textEncoding 编码方式"gb2312","utf-8" 默认是acii-->
      <server name="SuperSocketClass" 
       textEncoding="gb2312" 
       serverType="SuperSocketClass.Config.SocketServer,SuperSocketClass"
       ip="Any"
       port="2017"
       maxConnectionNumber="100">
      </server>
    </servers>
  </superSocket>


  <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
</configuration>

十、完整的工程项目

        从下图可以观察到,工程项目的解决方案名为:SuperSocketClass,即为实例名称

        从下图可以观察到,实例运行的AppServer类型为:SocketServer,它的全称为SuperSocketClass.Config.SocketServer。(因为自定义类SocketServer创建在Config文件夹下,因此它的全称为SuperSocketClass.Config.SocketServer)

十一、验证

1、启动服务器,创建客户端

2、连接客户端

 3、验证Hello类

客户端输入字符串"Hello C# SuperSocket Very Good!!!"。

警告:在客户端输入字符串,一定要按下回车键后才能点【发送数据】按钮,因为SuperSocket规定客户端给服务器发送的报文必须以"\r\n"为结束符,否则服务器会认为是非法报文不预处理。

 4、验证ADD类

客户端输入字符串"ADD 2 3 5"。

警告:在客户端输入字符串,一定要按下回车键后才能点【发送数据】按钮,因为SuperSocket规定客户端给服务器发送的报文必须以"\r\n"为结束符,否则服务器会认为是非法报文不预处理。

  5、验证MULT类

客户端输入字符串"MULT 2 3 5"。

警告:在客户端输入字符串,一定要按下回车键后才能点【发送数据】按钮,因为SuperSocket规定客户端给服务器发送的报文必须以"\r\n"为结束符,否则服务器会认为是非法报文不预处理。

6、验证Echo类

客户端输入字符串"Echo hello world!"。

警告:在客户端输入字符串,一定要按下回车键后才能点【发送数据】按钮,因为SuperSocket规定客户端给服务器发送的报文必须以"\r\n"为结束符,否则服务器会认为是非法报文不预处理。

 

注意事项:

  (1)、SocketServer、自定义命令和ScoketSession的访问权限必须设置为public

  (2)、 SocketServerr父类为AppServer<ScoketSession>

  (3)、 SocketSession父类为AppSession<ScoketSession>

  (4)、Hello父类为CommandBase<ScoketSession,StringRequestInfo>,ExecueteCommand方法传入值类型分别为ScoketSession和StringRequestInfo

  (5)、多服务器中需注意AppSession、AppServer、自定义命令中的AppSession不要搞错

总结:

        通过自定义Session和Server,可以实现我们自己的AppSession和AppServer允许你根据你业务的需求来方便的扩展SuperSocket,你可以绑定session的连接和断开事件,服务器实例的启动和停止事件。你还可以在AppServer的Setup方法中读取你的自定义配置信息。总而言之,这些功能让你方便的创建一个你所需要的socket服务器成为可能。

十二、源程序

        源程序参见如下链接:

C#SuperSocket手把手教你入门傻瓜教程-5(探索AppServer、AppSession,Conmmand)-C#文档类资源-CSDN文库

        源程序中包含SocketTool.exe TCP&UPD测试工具

        开发工具为:Visual Studio 2017

十三、致谢

SuperSocket入门(二)- 探索AppServer、AppSession,Conmmand和App.config - 黄昏前黎明后 - 博客园 (cnblogs.com)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值