在上一篇文章中,我们已经了解到了如何在SuperSocket处理客户端请求。 同时我们可能会发现一个问题,如果我们的服务器端包含有很多复杂的业务逻辑,这样的switch/case代码将会很长而且非常难看,并且没有遵循面向对象设计的原则(OOD)。 在这种情况下,SuperSocket提供了一些让我们在多个独立的类中处理各自不同的请求的命令框架,接下来我们一起来看一下怎么使用
    1、自定义AppSession
     AppSession 代表一个和客户端的逻辑连接,基于连接的操作应该放在该类之中。你可以用该类的实例发送数据到客户端,接收客户端发送的数据或者关闭连接。
     使用方法:创建自定义类MySession,继承AppSession类并重写AppSession类的方法(注意:一个AppSession对象对应一个连接)
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; /****************************************************************
* 作者:黄昏前黎明后
* CLR版本:4.0.30319.42000
* 创建时间:2017-01-19 00:02:17
* 2017
* 描述说明:自定义连接类MySession,继承AppSession,并传入到AppSession
*
* 修改历史:
*
*
*****************************************************************/
namespace SuperSocketDemo.Session
{ /// <summary>
/// 自定义连接类MySession,继承AppSession,并传入到AppSession
/// </summary>
public class MySession : AppSession<MySession>
{
/// <summary>
/// 新连接
/// </summary>
protected override void OnSessionStarted()
{
//输出客户端IP地址
Console.WriteLine(this.LocalEndPoint.Address.ToString());
this.Send("Hello User,Welcome to SuperSocket Telnet Server!");
} /// <summary>
/// 未知的Command
/// </summary>
/// <param name="requestInfo"></param>
protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
{
this.Send("unknow");
} /// <summary>
/// 捕捉异常并输出
/// </summary>
/// <param name="e"></param>
protected override void HandleException(Exception e)
{
this.Send("error: {0}", e.Message);
} /// <summary>
/// 连接关闭
/// </summary>
/// <param name="reason"></param>
protected override void OnSessionClosed(CloseReason reason)
{
base.OnSessionClosed(reason);
}
}
}

MySession类

    2、自定义AppServer
     AppServer 代表了监听客户端连接,承载TCP连接的服务器实例。理想情况下,我们可以通过AppServer实例获取任何你想要的客户端连接,服务器级别的操作和逻辑应该定义在此类之中。
    使用方法:创建自定义类MyServer,继承AppServer类并重写AppServer类的方法
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocketDemo.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; /****************************************************************
* 作者:黄昏前黎明后
* CLR版本:4.0.30319.42000
* 创建时间:2017-01-19 00:15:45
* 2017
* 描述说明:自定义服务器类MyServer,继承AppServer,并传入自定义连接类MySession
*
* 修改历史:
*
*
*****************************************************************/
namespace SuperSocketDemo.Server
{
/// <summary>
/// 自定义服务器类MyServer,继承AppServer,并传入自定义连接类MySession
/// </summary>
public class MyServer : AppServer<MySession>
{
protected override void OnStartup()
{
base.OnStartup();
// Console.WriteLine("服务器启动");
} /// <summary>
/// 输出新连接信息
/// </summary>
/// <param name="session"></param>
protected override void OnNewSessionConnected(MySession 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(MySession session, CloseReason reason)
{
base.OnSessionClosed(session, reason);
Console.Write("\r\n" + session.LocalEndPoint.Address.ToString() + ":断开连接");
} protected override void OnStopped()
{
base.OnStopped();
Console.WriteLine("服务已停止");
}
}
}

MyServer类

    3、使用Command
     在SuperSocket 中的Command让我们进行扩展,使用方法也极其简单。只需要继承一个CommandBase<AppSession, StringRequestInfo>类(注意:如果使用了自定义的Session,需要修改此处,如add类下的Add:CommandBase<MySession, StringRequestInfo>)类),并override这个类ExecuteCommand方法。现在我们来处理上篇文章的示例,先取消Telnet示例中的 appServer.NewRequestReceived 事件处理。这样我们就可以编写大量的命令让我们的Socket更灵活。
    例如,我们可以定义一个名为"Hello "的类去处理Key为"Hello"的请求:
 public class Hello: CommandBase<MySession, StringRequestInfo>
{
/// <summary>
/// 自定义执行命令方法,注意传入的变量session类型为MySession
/// </summary>
/// <param name="session">会话</param>
/// <param name="requestInfo">请求数据信息</param>
public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
{
session.Send(string.Format("Hello {0}:{1} {2}", session.Config.Ip, session.Config.Port, requestInfo.Body));
}
}

Hello类

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

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

Add类

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

public class MULT : CommandBase<MySession, StringRequestInfo>
{
public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
{
var result = ; foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p)))
{
result *= factor;
} session.Send(result.ToString());
}
}

Mult类

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

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

Echo类

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

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

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

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

配置完成后,还需要修改program类。将原有在program中定义的端口信息以及方法注释,只保留服务启动和停止的代码。引入using SuperSocket.SocketEngine;使用BootStrap启动

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketEngine;
using SuperSocketDemo.Server; /****************************************************************
* 作者:黄昏前黎明后
* CLR版本:4.0.30319.42000
* 创建时间:2017-01-19 00:02:17
* 2017
* 描述说明:服务启动和停止入口
*
* 修改历史: 2017 -01-19 调整自定义mysession和myserver
*
*
*****************************************************************/
namespace SuperSocketDemo
{
class Program
{
/// <summary>
/// SuperSocket服务启动或停止
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Console.WriteLine("请按任何键进行启动SuperSocket服务!");
Console.ReadKey();
Console.WriteLine();
var bootstrap = BootstrapFactory.CreateBootstrap(); if (!bootstrap.Initialize())
{
Console.WriteLine("初始化失败!");
Console.ReadKey();
return;
} //修改appserver为myserver
//var appServer = new AppServer();
// var appServer = new MyServer();
//注册事件
// appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected);
//appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived); //设置端口号
//int port = 2017;
//启动应用服务端口
//if (!appServer.Setup(port)) //启动时监听端口2017
//{
// Console.WriteLine("服务端口启动失败!");
// Console.ReadKey();
// return;
//} //Console.WriteLine(); ////尝试启动应用服务
//if (!appServer.Start())
//{
// Console.WriteLine("服务启动失败!");
// Console.ReadKey();
// return;
//}
var result = bootstrap.Start(); Console.WriteLine("服务正在启动: {0}!", result); if (result == StartResult.Failed)
{
Console.WriteLine("服务启动失败!");
Console.ReadKey();
return;
}
Console.WriteLine("服务启动成功,请按'E'停止服务!"); while (Console.ReadKey().KeyChar != 'E')
{
Console.WriteLine();
continue;
} //停止服务
// appServer.Stop();
bootstrap.Stop();
Console.WriteLine("服务已停止!");
Console.ReadKey();
}
/// <summary>
/// 在事件处理代码中发送欢迎信息给客户端
/// </summary>
/// <param name="session"></param>
//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;
// }
//}
}
}

program类

最后我们看一下修改后程序的运行结果:

断开调试工具看一下效果,可以看到服务端显示客户端断开连接

注意事项:

     a) MyServer、自定义命令和MySession的访问权限必须设置为public
     b) MyServer父类为AppServer<MySession>
     c) MySession父类为AppSession<MySession>
     d) HELLO父类为CommandBase<MySession,StringRequestInfo>,ExecueteCommand方法传入值类型分别为MySession和StringRequestInfo
     e) 多服务器中需注意AppSession、AppServer、自定义命令中的AppSession不要搞错
调试常见错误:
     

总结:

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

SuperSocket入门(二)- 探索AppServer、AppSession,Conmmand和App.config的更多相关文章

  1. java虚拟机入门(二)-探索内存世界

    上节简单介绍了一下jvm的内存布局以及简单概念,那么对于虚拟机来说,它是怎么一步步的让我们能执行方法的呢: 1.首先,jvm启动时,跟个小领导一样会根据配置参数(没有配置的话jvm会有默认值)向大领导 ...

  2. SuperSocket入门(三)-Telnet多服务实例和服务实例交互配置详解

        在SuperSocket入门(二)中我们已经简单了解了通过配置App.config文件使用BootStrap启动SuperSocket服务.我们先来看一下上个案例中的基本配置文件示例: < ...

  3. SuperSocket基础二

    SuperSocket基础(二)-----一个完整的SocketServer项目 由于时间关系未能及时更新,关于SuperSocket,对于初学者而言,一个SuperSock的Server真的不好写. ...

  4. IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

    1.系列文章引言 1.1 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...

  5. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  6. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

  7. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...

  8. Entity Framework 程序设计入门二 对数据进行CRUD操作和查询

    前一篇文章介绍了应用LLBL Gen生成Entity Framework所需要的类型定义,用一行代码完成数据资料的读取, <LLBL Gen + Entity Framework 程序设计入门& ...

  9. Swift语法基础入门二(数组, 字典, 字符串)

    Swift语法基础入门二(数组, 字典, 字符串) 数组(有序数据的集) *格式 : [] / Int / Array() let 不可变数组 var 可变数组 注意: 不需要改变集合的时候创建不可变 ...

随机推荐

  1. Extjs4---Cannot read property 'addCls' of null - heirenheiren的专栏 - 博客频道 - CSDN.NET

    body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLi ...

  2. 高效PHP编程

    1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍.   当然了,这个测试方法需要在十万级以上次执行,效果才明显.   其实静态方法和非静 ...

  3. windows2003 IIS6 部署MVC3和MVC4程序

    1.服务器上安装SP2 和 IIS6 2.安装.Net Framework3.5 SP1(完整安装包,包含2.0 2.0SP1,237MB那个安装包) 3.安装.Net Framework4.0 4. ...

  4. Sping--AOP--XML

    IoC: annotation AOP: XML XML比annotation用的多. beans.xml: <?xml version="1.0" encoding=&qu ...

  5. CentOS 7 源码编译安装 Mysql 5.7

    1.创建 mysql 用户,用户组,以及相关目录 /usr/sbin/groupadd mysql /usr/sbin/useradd -g mysql mysql mkdir -p /opt/loc ...

  6. 浅谈mysql主从复制的高可用解决方案

    1.熟悉几个组件(部分摘自网络)1.1.drbd     —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID" ...

  7. Oracle物化视图的用法与总结

    物化视图(material view)是什么? 物化视图是包括一个查询结果的数据库对象,它是远程数据的的本地副本,或者用来生成基于数据表求和的汇总表. 物化视图存储基于远程表的数据,也可以称为快照(类 ...

  8. LPC2478的外部中断使用

    LPC2478外部中断 2478的外部中断模型如下 也就是说,port0和2支持外部中断,EINT0-2是三个独立管脚的中断,而EINT3则是port0和2的所有中断共同拥有的向量 对于port0和2 ...

  9. camstar --飞达上料

    业务场景:某工厂的SMT车间接到生产PCB(3151502),数量1000片.如果实现飞达进行上料,并在贴片机工作时,系统自动进行物料消耗.3151502的BOM为1107790,1107792,11 ...

  10. IOS开发-UI学习-delegate(代理)的使用,键盘消失

    代理是IOS开发中用到的一种设计模式.今天做了一个代理的小练习: 以下项目实现了两个页面之间的相互切换,并且在切换页面的时候完成了从一个页面往另一个页面的传值.从主页面往其他页面传值是容易的,但是反过 ...