[转] C# SuperSocket 手把手教你入门 傻瓜教程 5~6
5(探索自定义AppServer、AppSession,Conmmand,用配置文件App.comfig启动服务器)
目录
一、为什么要使用自定义类AppServer、AppSession,Conmmand
3、log4net.config的【复制到输出目录】组态为“如果较新则复制”
(一)、定义一个名为"Hello "的类去处理Key为"Hello"的请求。
(二)、定义一个名为"ADD"的类去处理Key为"ADD"的请求:
(三)、定义一个名为"MULT"的类去处理Key为"MULT"的请求:
(四)、定义一个名为"Echo"的类去处理Key为"Echo"的请求:
九、配置App.config使用BootStrap启动SuperSocket
在前几篇文章中,我们已经了解到了如何在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启动服务器
- 避免硬编码
- SuperSocket提供了很多有用的配置选项
- 可以充分利用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服务器成为可能。
转自https://blog.csdn.net/ba_wang_mao/article/details/1281457466(CommandLineProtocol---命令行协议)
目录
1、SuperSocket命令行协议定义了每个请求必须以回车换行符( "\r\n")结尾。
2、SuperSocket命令行协议将接收到的数据翻译成StringRequestInfo 实例。
3、SuperSocket 内置的命令行协议用空格来分割请求的Key和参数部分。
4、SuperSocket 内置的命令行协议的参数部分用空格来分割。
四、安装SuperSocket和SuperSocket.Engine
1、工程项目中添加一个自定义类LOGIN,处理Key为"LOGIN"的请求。
九、配置App.config使用BootStrap启动SuperSocket
构建一个网络应用程序, 仅仅使用 TCP 还是 UDP 是远远不够的。 因为TCP 和 UDP 是传输层协议。定义了传输层协议是不能让网络的两端进行通信的。需要定义应用层通信协议把接收到的二进制数据转化成你程序能理解的请求。
Socket里面的协议解析是Socket通讯程序设计中最复杂的地方,如果你的应用层协议设计或实现不佳,Socket通讯中常见的粘包和分包就难以避免,而用SuperSocket提供的通信协议就完美的避免了上述情况的发生。
一、 SuperSocket提供的通信协议
SuperSocket提供以了下几种应用层通信协议。
- CommandLineProtocol---命令行协议(默认内置)
- 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)---头部格式固定并包含内容长度协议
什么是默认内置?当你不定义应用层通信协议,直接用AppSession.Send()方法发送字符串进行服务器和客户端双向通信,SuperSocket就默认启用命令行协议CommandLineProtocol。
下图的代码,你不定义应用层通信协议,直接用AppSession.Send()方法发送字符串进行服务器和客户端双向通信,SuperSocket就默认启用命令行格式的协议CommandLineProtocol进行通信。
- static void appServer_NewSessionConnected(AppSession session)
- {
- session.Send("Welcome to SuperSocket Telnet Server!");
- }
二、命令行协议CommandLineProtocol
命令行协议是一种被广泛应用的协议。一些成熟的协议如 Telnet, SMTP, POP3 和 FTP 都是基于命令行协议的。
在SuperSocket 中,如果我们没有自定义应用层协议的话,SuperSocket默认的协议就是命令行协议 ,这样就极大的简化了基于此类协议的开发。
1、SuperSocket命令行协议定义了每个请求必须以回车换行符( "\r\n")结尾。
2、SuperSocket命令行协议将接收到的数据翻译成StringRequestInfo 实例。
SuperSocket设计了两个RequestInfo类:StringRequestInfo 和BinaryRequestInfo。其中StringRequestInfo用于字符串实例,BinaryRequestInfo用于二进制实例。如果我们在SuperSocket中使用命令行协议,所有接收到的数据都会翻译成 StringRequestInfo实例(字符串实例)。我们来看一下StringRequestInfo的定义:
- public class StringRequestInfo
- {
- public string Key { get; }
- public string Body { get; }
- public string[] Parameters { get; }
- /* Other properties and methods */
- }
StringRequestInfo有三个属性, Key是这个命令行协议的命令名,用于关联Command的字符串;Body是一个命令的参数部分;Parameters是一个命令的参数列表。
3、SuperSocket 内置的命令行协议用空格来分割请求的Key和参数部分。
SuperSocket内置的命令行协议用空格来分割请求的Key和参数部分,因此当客户端发送如下数据到服务器端时
"LOGIN kerry 123456" + 回车换行符
服务器将会收到一个StringRequestInfo 实例,这个实例的属性为:
Key: "LOGIN"
Body: "kerry 123456";
Parameters: ["kerry", "123456"]
同时定义 "LOGIN" 的命令,这个命令的 ExecuteCommand 方法将会被执行,服务器所接收到的StringRequestInfo实例也将作为参数传给这个方法。
- public class LOGIN : CommandBase<AppSession, StringRequestInfo>
- {
- public override void ExecuteCommand(AppSession session, StringRequestInfo requestInfo)
- {
-
- }
- }
4、SuperSocket 内置的命令行协议的参数部分用空格来分割。
SuperSocket内置的命令行协议的参数部分用空格来分割,因此当客户端发送如下数据到服务器端时:
"LOGIN kerry 123 456 789" + 回车换行符
服务器将会收到一个StringRequestInfo 实例,这个实例的属性为:
Key: "LOGIN"
Body: "kerry 123 456 789";
Parameters: ["kerry", "123", "456", "789"]
其中:Parameters[0]="kerry",Parameters[1]="123",Parameters[2]="456",Parameters[3]="789"
下面我们创建一个命令行协议的项目验证SuperSocket 内置的命令行协议CommandLineProtocol
三、创建一个支持命令行协议的工程项目
新建一个SuperSocket服务器项目SuperSocketCommandLineProtocol,参见下图。
四、安装SuperSocket和SuperSocket.Engine
1、进入【管理NuGet程序包】
鼠标右键单击【引用】,弹出下拉菜单,在下拉菜单中选中【管理NuGet程序包(N)】
2、安装SuperSocket
(1)、【浏览】选项卡下面的输入框中输入SuperSocket
(2)、过一会下面会出现"SuperSocket ......下载 v1.6.6.1"
(3)、鼠标点击"SuperSocket ......下载 v1.6.6.1",右边会出现"版本:最新稳定版1.6.6.1"
(4)、点击"版本:最新稳定版1.6.6.1"右边的【安装】按钮
3、安装SuperSocket.Engine
(1)、鼠标点击"SuperSocket.Engine ",右边会出现"版本:1.6.6.1"
(2)、点击"版本:1.6.6.1"右边的【安装】按钮
五、自定义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 SuperSocketCommandLineProtocol
- {
- /// <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 SuperSocketCommandLineProtocol.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下,因此完整的路径是:
SuperSocketCommandLineProtocol.Config
七、使用Command
在SuperSocket中的Command让我们进行扩展,使用方法也极其简单。只需要继承一个CommandBase<AppSession, StringRequestInfo>类。(注意:如果使用了自定义的Session,需要修改此处,如LOGIN类下的LOGIN:CommandBase<SocketSession, StringRequestInfo>)类),并override这个类ExecuteCommand方法。
1、工程项目中添加一个自定义类LOGIN,处理Key为"LOGIN"的请求。
2、LOGIN类完整的代码如下:
- 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 SuperSocketCommandLineProtocol
- {
- public class LOGIN : 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("LOGIN {0}:{1} {2}", session.Config.Ip, session.Config.Port, requestInfo.Body));
- }
- }
- }
八、program.cs
在program.cs类中改为使用App.config文件配置,用BootStrap启动服务器。
警告:要想使用BootStrap启动服务器,必须引用
using SuperSocket.SocketEngine;
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;
-
-
-
- namespace SuperSocketCommandLineProtocol
- {
- class Program
- {
- static void Main(string[] args)
- {
- 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;
- }
-
- //停止服务
- 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="SuperSocketCommandLineProtocol"
- textEncoding="gb2312"
- serverType="SuperSocketCommandLineProtocol.Config.SocketServer,SuperSocketCommandLineProtocol"
- ip="Any"
- port="2017"
- maxConnectionNumber="100">
- </server>
- </servers>
- </superSocket>
这里解释一下配置的服务器节点:
name: 实例名称(就是:工程项目的解决方案名称:SuperSocketCommandLineProtocol)
serverType: 实例运行的AppServer类型(就是之前我们创建的自定义AppServer类【SocketServer】,它创建在Config文件夹下,因此的完整路径为:SuperSocketCommandLineProtocol.Config.SocketServer)
ip: 侦听ip
port: 侦听端口
name: 实例名称 ---> SuperSocketCommandLineProtocol
serverType: ---> SuperSocketCommandLineProtocol.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="SuperSocketCommandLineProtocol"/>
- <add key="ServiceDescription" value="霸王猫"/>
- </appSettings>
-
-
- <!--SuperSocket服务配置信息 serverType是项目的服务如我自定义的Socketserver-->
- <!--name: 实例名称
- serverType: 实例运行的AppServer类型
- ip: 侦听ip
- port: 侦听端口-->
- <superSocket>
- <servers>
- <!--textEncoding 编码方式"gb2312","utf-8" 默认是acii-->
- <server name="SuperSocketCommandLineProtocol"
- textEncoding="gb2312"
- serverType="SuperSocketCommandLineProtocol.Config.SocketServer,SuperSocketCommandLineProtocol"
- ip="Any"
- port="2017"
- maxConnectionNumber="100">
- </server>
- </servers>
- </superSocket>
-
-
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
- </startup>
- </configuration>
十、验证
1、启动服务器
服务器启动成功。
2、启动客户端
3、连接客户端
连接客户端后,客户端收到服务器发送的信息:“Hello User,Welcome to SuperSocket Telnet Server!”
4、客户端发送字符串“LOGIN kerry 123 456 789”+回车换行符
为了更好理解和明白,我们看一下调试的参数:
服务器收到一个StringRequestInfo 实例,这个实例的属性为:
转自https://blog.csdn.net/ba_wang_mao/article/details/128220289Key: "LOGIN"
Body: "kerry 123 456 789";
Parameters: ["kerry", "123", "456", "789"]其中:
Parameters[0]="kerry",
Parameters[1]="123",
Parameters[2]="456",
Parameters[3]="789"