什么是AppSession和AppServer
AppSession代表一个逻辑Socket连接,基于连接的操作都应该在这个类中来定义。我们可以使用AppSession向顶层的客户端发送数据,从连接接收数据或者是关闭一个连接。
AppServer是Socket服务器的实例,它坚挺着所有客户端的连接,管理所有顶层客户端的连接。理想状况下,我们可以从AppServer中找到任意一个Session。应用级的操作和逻辑应该在这里定义。
创建自己的AppSession
- Super Socket的可扩展性较高,我们可以通过继承AppSession这个类并覆盖其中的方法来创建自己的AppSession(如下面的代码)。
- 可以genju yewuxuqiu 为你的Session添加新的属性,下面我们来创建一个奖杯用于游戏服务器的AppSession。
- 与Commands的关系 第一篇文章中,提到过commands,这里再来看看。
public class TelnetSession : AppSession<telnetsession> { protected override void OnSessionStarted() { this.Send("Welcome to SuperSocket Telnet Server"); } protected override void HandleUnknownRequest(StringRequestInfo requestInfo) { this.Send("Unknow request"); } protected override void HandleException(Exception e) { this.Send("Application error: {0}", e.Message); } protected override void OnSessionClosed(CloseReason reason) { //添加自己需要的业务逻辑,它们将在Session关闭后被执行 base.OnSessionClosed(reason); } }
※注意:AppSession是一个抽象类,上述方法在父类中都是空方法,不进行任何操作。这里我们不难发现,TelnetSession继承了AppSession(我是第一次见到用泛型来继承的),覆盖了父类的4个方法。OnSessionStarted方法即是在连接建立之后服务器立即向客户端发送一条欢迎信息“Welcome to SuperSocket Telnet Server”。
public class PlayerSession :AppSession<PlayerSession> { public int GameHallId { get; internal set; } public int RoomId { get; internal set; } }
public class ECHO : CommandBase<AppSession, StringRequestInfo> { public override void ExecuteCommand(AppSession session, StringRequestInfo requestInfo) { session.Send(requestInfo.Body); } }
在上面的代码中,不难发现,ECHO的父类是带有泛型参数(AppSession)的CommandBase。这就是其默认的AppSession。如果你想使用自己新创建的AppSession,就需要传递你自己的AppSession的类型,否则服务器是不能发现此command:
public class ECHO : CommandBase<PlayerSession, StringRequestInfo> { public override void ExecuteCommand(PlayerSession session, StringRequestInfo requestInfo) { session.Send(requestInfo.Body); } }
创建自己的AppServer
- 如果你想使用自己的AppSession,你必须修改你的AppServer。
- AppServer中有许多protected方法可供覆盖
public class TelnetServer : AppServer<TelnetSession> { }
简单说来,就是继承AppServer,并把自己定义的Session(继承AppSession)作为泛型参数。如上面代码所示,TelnetSession就可以在TelnetServer中被使用了。
public class TelnetServer : AppServer<TelnetSession> { protected override bool Setup(IRootConfig rootConfig, IServerConfig config) { return base.Setup(rootConfig, config); } protected override void OnStartup() { base.OnStartup(); } protected override void OnStopped() { base.OnStopped(); } }
好处及优点
实现自定义的AppSession和AppServer允许你按照自己的业务需求扩展SuperSocket。你可以监视(程序钩子)session的连接、关闭事件,server实例的启动和停止。你可以在AppServer的Setup()方法中读取自定义的配置。总而言之,它提供了大量用来构建你切实所需的自己的socket服务器的功能。
这次几乎又是纯翻译,其实作者已经发布了1.4的中文文档。我在这里翻译,主要是督促自己用心学习其中内容。如果我在完成其翻译后作者仍未发布1.5的中文文档,我希望能够在codeplex上更新中文文档,以尽绵薄之力。
本文中的代码我一行也没有自己调试过,觉得只要知道SuperSocket有这么回事就可以了但我一定写个小程序来试试文中的要点。我的学习方式受马士兵的影响很大,从这种学习项目的命名就可以看出。虽然我在看他的Struts2视频时,有些东西感觉不敢苟同,但这种学习方式认为还是可取的。
我已经写好了这个程序,并且调试通过了。我自定义了一个TelnetServer和TelnetSession,TelnetServer里并没有添加自己的逻辑,需要的话,一些日志记录可以放到这里。TelnetSession里添加了两个属性,覆盖了几个方法,例如覆盖了Send(string message)这个方法。创建了ECHO.cs以处理客户端的ECHO请求。以下是源码。
- TelnetServer.cs
- TelnetSession.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; namespace SuperSocket_0200_AppServerAppSession { public class TelnetSession:AppSession<TelnetSession> { public int UserId { get; internal set; } public string Username { get; internal set; } protected override void OnSessionStarted() { this.Send("Welcome to SuperSocket Server!"); UserId = 1; Username = "test"; } public override void Send(string message) { string prefix = Username + "(" + UserId + "):"; base.Send(prefix+message); } protected override void HandleException(Exception e) { this.Send("Application error: {0}", e.Message); } protected override void OnSessionClosed(CloseReason reason) { //添加自己需要的业务逻辑,它们将在Session关闭后被执行 base.OnSessionClosed(reason); } } }
- ECHO.cs
- Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; namespace SuperSocket_0200_AppServerAppSession { public class TelnetServer:AppServer<TelnetSession> { protected override bool Setup(IRootConfig rootConfig, IServerConfig config) { return base.Setup(rootConfig, config); } protected override void OnStartup() { base.OnStartup(); } protected override void OnStopped() { base.OnStopped(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase.Command; using SuperSocket.SocketBase.Protocol; namespace SuperSocket_0200_AppServerAppSession { public class ECHO:CommandBase<TelnetSession,StringRequestInfo> { public override void ExecuteCommand(TelnetSession session, StringRequestInfo requestInfo) { session.Send(requestInfo.Body); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SuperSocket_0200_AppServerAppSession { class Program { static void Main(string[] args) { Console.WriteLine("Press any key to start the server!"); Console.ReadKey(); Console.WriteLine(); TelnetServer appSrv = new TelnetServer(); //启动服务器 if (!appSrv.Setup(2012))//启动服务器并监听2012端口 { Console.WriteLine("Failed to setup"); Console.ReadKey(); return; } Console.WriteLine(); //Try to start the appServer if (!appSrv.Start()) { Console.WriteLine("Failed to start!"); Console.ReadKey(); return; } ////添加会话连接委托事件 //appSrv.NewSessionConnected += new SessionHandler(appSrv_NewSessionConnected); ////添加收到请求后的委托事件 //appSrv.NewRequestReceived += new RequestHandler(appSrv_NewRequestReceived); Console.WriteLine("The server started successfully, press key \"q\" to stop it. "); while (Console.ReadKey().KeyChar != 'q') { Console.WriteLine(); continue; } //Stop the appServer appSrv.Stop(); Console.WriteLine("The server was stopped"); Console.ReadKey(); } } }
没有评论:
发表评论