前几天终于把开题报告写好了,这玩意儿着实令人厌烦。你不写吧,交不了差。但写了又没多大用处,无非是抄点前人的老话、套话——你还得小心别抄袭了,不过总算是完成了。我要做的是基于WebSocekt的一个监控系统,JAVA已经有不少像Tomcat、JBoss等服务器级的支持,而.NET这边却很少。IIS8支持WebSocket,但需要WIN8,我懒得折腾系统,就找了一个开源的WebSocekt Server的实现:WebSocket4Net,是SuperWebSocket为了方便.NET程序员进行WebSocket开发而衍生的一个版本。而SuperWebSocket又是基于SuperSocket。
我曾询问过作者(该项目是国人开发的)SuperSocket的性能如何,得到的答复是在一台较主流的笔记本上可以达到每秒1万次的并发。我虽然不敢妄加评论这个性能是好是坏,但至少比之前使用的Comet及其实现(AspNetComet)那据说是只有200的并发要好得多。况且这并不是一个商业项目,作为本科毕业设计,做出来的东西本来就是实验、探究性质,对性能的要求可以适当降低。下面是我研究SuperSocket 1.5的开发者文档,而做的笔记和测试。根据我的需求,文档中最后3个或4个我可能不会去研究。
虽然说是学习和研究,其实主要是跟着文档中的操作自己再做一遍,并把英文的文档翻译一下。一些我遇到了而原文档中没有详细说明的地方我也会提出来。
但当我写到这篇文章的末尾我发现SuperSocket并不能直接应用于我的项目,我要用的是WebSocket4Net。当然研究一下根儿也是不错的,只是我可能不会那么用心了。
这一节讲述了用Super Socket搭建一个telnet服务器并使用windows的telnet客户端进行测试的步骤。同时还说明了Super Socket的依赖关系、核心组件以及初步的使用方法。
Super Socket的核心组件有3个,分别是:SuperSocket.Common.dll、SuperSocket.SocketBase.dll、SuperSocket.SocketEngine.dll。另外,Super Socket使用了log4net作为其默认的日志系统,所以在项目中使用时需要添加引用这4个dll文件(包括log4net.dll)。
创建一个控制台应用程序并添加Super Socket的相关引用
- 下载Super Socket的程序集。源码或已编译的dll均可,注意Super Socket编译的.NET版本要跟自己的项目一致。然后创建一个控制台应用程序,需要注意的是编译的平台选择.NET 3.5或4.0这样的完全版,而不要选择Client Profile。项目建立后仍可以在该项目的“属性”中查看\更改这一属性。
- 复制上面提到的4个dll到项目的bin目录,并添加这些引用。同时,如果没有项目没有引用System.Configuration,也需要一并添加,Super Socket需要用到这一程序集。
- 将Super Socket中的对应.NET版本目录下的Config文件夹复制到自己项目的根目录下。
编写启动/停止服务器代码
原文中只给出了Main方法里的代码,且仅限于服务器的启停,没有后文中各种测试的支持。虽然这对开发者来说应该不会造成太大的障碍,但我仍然在这里贴出完整的,经我测试可以运行的代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; namespace SuperSocket_0100_TalnetExample { class Program { static void Main(string[] args) { Console.WriteLine("Press any key to start the server!"); Console.ReadKey(); Console.WriteLine(); AppServer appSrv = new AppServer(); //启动服务器 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(); } //向客户端发送欢迎信息 static void appSrv_NewSessionConnected(AppSession session) { session.Send("Welcome to SuperSocket Telnet Server!"); } //处理客户端请求,这里定义了ECHO,ADD,MULT 3种操作 static void appSrv_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"): int result = 1; foreach (int factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p))) { result *= factor; } session.Send(result.ToString()); break; } } } }
需要说明的是,注意引用必要的命名空间。在CodePlex上有人问到过这样的问题:StringRequestInfo这个类找不到。这个类在SuperSocket.SocketBase.Protocol命名空间下,需要在代码中添加using语句才可使用。
使用Telnet客户端进行测试
WIN7默认没有安装Telnet的服务端和客户端。需要用户手动开启,在“控制面板”——“打开或关闭Windows功能”中勾选Telnet服务端(可选)和Telnet客户端,然后需要在服务中启动Telnet服务才能完成下面的测试。
- 启动服务器程序,按任意键启动服务器。
- 打开telnet客户端,这里我使用windows自带的客户端。
- 输入“telnet localhost 2012”,回车
- 首先会得到欢迎信息,随后可输入ADD 2 3或ECHO Hello这样的命令。前者会返回两数之和,后者会原样输出字符串,如图。
命令行的用法(以下代码我并未测试)
前面这种switch-case的方式在处理复杂业务逻辑时显得十分臃肿,也不符合面向对象设计(OOD)的要求。Super Socket提供这样一个框架,允许定义独立的类来处理不同的请求。我们只需要继承CommandBase这个类,并覆盖ExecuteCommand方法即可。
例如,可以定义个名为ADD的类,来处理客户端发送过来的ADD请求(大小写敏感的)。
public class ADD : CommandBase<AppSession, StringRequestInfo> { public override void ExecuteCommand(AppSession session, StringRequestInfo requestInfo) { session.Send(requestInfo.Parameters.Select(p => Convert.ToInt32(p)).Sum().ToString()); } }
同理,MULT类,用来处理名为MULT的请求
public class MULT : CommandBase<AppSession, StringRequestInfo> { public override void ExecuteCommand(AppSession session, StringRequestInfo requestInfo) { var result = 1; foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p))) { result *= factor; } session.Send(result.ToString()); } }
上面这种方式与添加委托事件的方式会产生冲突,需要移除前面第一段代码中的高亮部分。(委托事件的方法也可一并移除或注释掉)
没有评论:
发表评论