最简单的C/S程序——让服务器来做加法
还在写“Hello world!”式的单机程序吗?还在各种拖控件吗?是否自己都觉得有点low呢?来个质的飞跃吧!看看怎么让服务器帮咱做加法!
所谓C/S程序就是Client/Server程序,自然既包含一个Client项目,又包含一个Server项目。所以先来新建解决方案及项目。
一·开端
1.新建解决方案及项目 (针对初学者,已掌握者跳过)
1.新建一个Windows窗体项目,项目命名为Server。
2.右击右击解决方案,添加新建项目,命名为Client.
现在,传说中的C/S架构就已经初现端倪了。
既然是C/S程序,必然涉及Client和Server之间的通信,这也是C/S程序和单机程序最大的区别。同时也是初学者进步路上的拦路虎。问题的关键正是在于如何实现Client和Server之间的通信。可是今天我们不必纠结于任何关于网络通信技术的琐碎与繁难,却能够妥善,简约,完美的将问题解决,而这就需要我们站在巨人的肩膀上。所谓“君子性非异也,善假于物也。”,这里我们要借助于稳定强大的ESFramework通信框架,利用它来实现我们将加法交给服务器来做的小小心愿。(怎么感觉有点杀鸡用牛刀呢?)
2·添加引用(针对初学者,已掌握者跳过)
右击项目,添加引用。
Client和Server两个项目都要引用哦。
二·核心实现
好了,现在宝贝已经搞到手了。可是宝贝再好,不会用也是白搭。ESFramework究竟怎么用呢?更具体一点,究竟如何用它来帮助我们实现把加法交给服务器来做的需求呢?这就需要用到 ESFramework提供给我们的两件利器:RapidServerEngine(服务端通信引擎)和 RapidPassiveEngine(客户端通信引擎)。其实说到底,天下只有一件利器,那就是Engine(通信引擎),它分为服务端和客户端两部,配合使用方能鸾凤和鸣!虽然引擎二字听起来充满了工业时代的气息,但实际上这台引擎并不像我们想象的那样笨重、机械,相反,它更像当今时代我们人手一部的手机,小巧轻便却功能超强!随时随地通信无阻! 有了这两部引擎,服务端和客户端便能畅爽的通信!
既然通信的核心部件就是这两部引擎,那么我们不妨先将他们装配到我们的项目中再说!
1·装配通信引擎
(1)服务端装配通信引擎
namespace Server
{
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//创建服务端引擎
IRapidServerEngine serverEngine = RapidEngineFactory.CreateServerEngine();
ServerHandler serverHandler = new ServerHandler();
Application.Run(new Form1());
}
}
}
之所以在Main()方法中来创建serverEngine,是因为serverEngine是承担通信重任的核心部件,所以在程序运行之初就要准备好。(当然,Main方法是应用程序的主入口点这个大家都知道。)要注意的一点是:一定要在 Application.Run(new Form1());语句之前添加代码哦,因为窗体跑起来之后,后面的代码就不会被执行了,大家可以自己动手试一下。另外,大家自己在照着添加上述代码的时候,会出现红色下划线的情况,不要紧张,光标放上去,然后会有蓝色小短杠出现,光标再移上去,添加Using即可。
(2)客户端装配通信引擎
namespace Client
{
static class Program
{
//创建客户端通信引擎,公有静态方便外部调用
public static IRapidPassiveEngine clientEngine = ESPlus.Rapid.RapidEngineFactory.CreatePassiveEngine(); static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
2·实现消息处理器
接下来我们要做第二个重要部署,同时,ESFramework为我们提供的第二个法宝也要粉墨登场了!那就是CustomizeHandler(自定义消息处理器)。收发消息的重任已经由Engine(通信引擎)一力承担了,而处理消息的重任就交给CustomizeHandler(自定义消息处理器)了!
既然是自定义消息处理器,那么肯定是留给程序员自己来添加相应的处理逻辑的,ESFramework通信框架为此预留了ICustomizeHandler接口,所以我们自己添加一个类来实现ICustomizeHandler接口。
(1)服务端添加ServerHandler类
namespace Server
{
class ServerHandler : ICustomizeHandler//实现接口
{
public void HandleInformation(string sourceUserID, int informationType, byte[] info)
{
throw new NotImplementedException();
} public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info)
{
throw new NotImplementedException();
}
}
}
(2)客户端添加ClientHandler类(与服务端类似,略)
(3)服务端装配消息处理器
namespace Server
{
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//创建服务端引擎
IRapidServerEngine serverEngine = RapidEngineFactory.CreateServerEngine();
//创建服务端消息处理器
ServerHandler serverHandler = new ServerHandler();
Application.Run(new Form1());
}
}
}
(4)客户端装配消息处理器(与服务端类似,略)
3·通信引擎初始化
接下来我们要做一件重要的工作了:通信引擎初始化!
(1)服务端引擎初始化
对于serverEngine(服务端通信引擎),我们需要设置好用于通信的端口号,并且将之前创建好的serverHandler(服务端消息处理器)装配到serverEngine中。这是因为,收到消息是处理消息的前提,当Engine收到消息后就需要对收到的消息进行相关处理,而这正是Handler的职责,所以Engine要将Handler包含其中才能够方便的把收到的消息就地进行处理。
namespace Server
{
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//创建服务端引擎
IRapidServerEngine serverEngine = RapidEngineFactory.CreateServerEngine();
//装配服务端消息处理器
ServerHandler serverHandler = new ServerHandler();
//设置好服务器用来通信的端口号,并将消息处理器传入引擎
serverEngine.Initialize(2000, serverHandler);
Application.Run(new Form1());
}
(2)客户端引擎初始化
对于clientEngine(客户端通信引擎)而言则需要设置好用户ID,登陆密码,欲要连接的服务器IP及端口号,同时也要装配好clientHandler。
namespace Client
{
static class Program
{
//创建通信引擎,公有静态方便外部调用
public static IRapidPassiveEngine clientEngine = ESPlus.Rapid.RapidEngineFactory.CreatePassiveEngine(); static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//创建客户端消息处理器
ClientHandler clientHandler = new ClientHandler();
//初始化客户端引擎,该操作将与目标服务器建立TCP连接,方法返回值为登陆的结果状态
LogonResponse logonResponse = clientEngine.Initialize("1", "123", "127.0.0.1", 2000, clientHandler);
Application.Run(new Form1());
}
}
}
三·业务逻辑编写
上述过程其实都是准备工作,主要就是引用ESFramework通信框架并将框架提供的重要“设备”(通信引擎和消息处理器)准备到位,这样一来,之前探讨得出的核心问题,即如何实现客户端与服务端之间的通信,就已经不成问题了,现在我们就可以考虑利用ESFramework提供的相关API来编写我们的业务逻辑了!
1.客户端向服务端发送消息
客户端向服务器发送消息的核心就是利用框架提供的clientEngine.CustomizeOutter.Send(int informationType, byte[] info)方法,来把待相加的两个整数打包发送给服务器,并附加消息类型为做加法,这样服务器在收到消息后就可以将消息解析出来并进行相应的处理了。
private void button1_Click(object sender, EventArgs e)
{
int leftNum = int.Parse(this.textBox_leftNum.Text);
int rightNum = int.Parse(this.textBox_rightNum.Text);
//将数据转码以备发送给服务端
byte[] leftNumCode = BitConverter.GetBytes(leftNum);
byte[] rightNumCode = BitConverter.GetBytes(rightNum);
byte[] NumbersCode = new byte[8];//用来合并待发送的消息(一个整型占4个字节)
for (int i = 0; i < 4; i++)
{
NumbersCode[i] = leftNumCode[i];//第一个数的编码装进前四位
}
for (int j = 0; j < 4; j++)
{
NumbersCode[j + 4] = rightNumCode[j];//第二个数的编码装进后四位
}
//发送给服务器,100代表做加法这件事
Program.clientEngine.CustomizeOutter.Send(100, NumbersCode);
}
2.服务端接收并处理消息,并将处理结果发送给客户端
服务端的通信引擎serverEngine将自动接收到客户端发送过来的消息,并且将接收到的消息递交给消息处理器serverHandler来处理,这也是之前为什么要把serverHandler传递进来的原因。现在我们要做的就是去ServerHandler类中来编写相应的处理逻辑。但是要注意一点,那就是ServerHandler在处理完消息后需要将处理结果再发送给客户端,而收发消息是通信引擎的职责,所以我们需要将serverEngine作为参数传进来。而发送消息仍然要仰仗框架提供的serverEngine.CustomizeController.Send(string userID, int informationType, byte[] info)方法。
class ServerHandler : ICustomizeHandler//实现接口
{
private IRapidServerEngine serverEngine; public ServerHandler(IRapidServerEngine _serverEngine)
{
this.serverEngine = _serverEngine;
}
//该方法用来处理客户端通过clientEngine.CustomizeOutter.Send()方法发送过来的消息
public void HandleInformation(string sourceUserID, int informationType, byte[] info)
{
if (informationType == 100)
{
int leftNum = BitConverter.ToInt32(info, 0);//将字节数组前四位还原成leftNum
int rigthNum = BitConverter.ToInt32(info, 4);//将字节数组后四位还原成rigthNum
int result = leftNum + rigthNum;
byte[] resultCode = BitConverter.GetBytes(result);//将计算结果转码
this.serverEngine.CustomizeController.Send(sourceUserID, 100, resultCode);//发送给对应的客户端
}
}
//该方法用来处理客户端发送过来的请求,那是另一种通信方式,这里姑且不论
public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info)
{
throw new NotImplementedException();//接口的默认实现
}
}
3.客户端接收并分析消息,并将结果显示到界面
客户端通信引擎clientEngine收到消息后仍然需要交付给消息处理器ClientHandler来处理。
class ClientHandler : ICustomizeHandler
{
//该方法来处理服务端Send()方法发送过来的消息
public void HandleInformation(string sourceUserID, int informationType, byte[] info)
{
if (informationType == 100)
{
MessageBox.Show("结果为:" + BitConverter.ToInt32(info, 0));
}
} public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info)
{
throw new NotImplementedException();
}
}
四·编译运行
1.先启动服务端,右击Server项目,调试,启动新实例
2.启动客户端
大功告成!
五·总结
虽然本文篇幅较长但是整个逻辑其实非常简单!之所以篇幅较长主要是因为花了较多的笔墨照顾初学者,同时也是因为尽力在营造循序渐进的逻辑过程,为了让每一步水到渠成,不突兀,不跳跃,惟其如此才是符合认识论的学习过程,同时也是我们实际编程中应该掌握的思维方式。
回头来看,其实所有的工作只分为两步:
1.引用通信框架并做好相关的准备工作,使得“如何实现通信”这一重要艰巨的问题刹那间迎刃而解!
2.编写相关的业务逻辑。
而1中的工作是超简单的,一回生二回熟,以后无论编任何C/S程序都是这个套路,从此我们只需要专注于具体的业务逻辑而不用理会关于底层通信技术的一切琐碎与繁难了!而这将大大提高工作效率!
转自:http://www.cnblogs.com/aoyeyuyan/p/4347540.html
最简单的C/S程序——让服务器来做加法的更多相关文章
- 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法
(本文是专门针对未接触过C/S开发的初学者而写的,C/S开发高手请自动忽略啊~~) 还在写“Hello world!”式的单机程序吗?还在各种拖控件吗?是否自己都觉得有点low呢?来个质的飞跃吧!看看 ...
- 用CIL写程序:写个函数做加法
前言: 上一篇文章小匹夫为CIL正名的篇幅比较多,反而忽略了写那篇文章初衷--即通过写CIL代码来熟悉它,了解它.那么既然有上一篇文章做基础(炮灰),想必各位对CIL的存在也就释然了,兴许也燃起了一点 ...
- 循序渐进做项目系列(2):最简单的C/S程序——消息异步调用与消息同步调用
上篇博客 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法 实现了一个最简单的C/S程序,即让服务器来做加法.当时为了通俗易懂采用了消息异步调用的方式.今天我们要采用消息同步调用的方式 ...
- 自己动手写一个简单的(IIS)小型服务器
因为第一次在博客园发表随笔,不太会用,这个笔记是我之前在印象笔记中写好的,然后直接copy过来,有兴趣自己做一个IIS服务器的小伙伴们可以参照下面的流程做一次,也可以叫我要源代码,不过要做完,我觉得花 ...
- C#简单实现贪吃蛇程序(LinQ + Entity)
做梦想起来的C#简单实现贪吃蛇程序(LinQ + Entity) 最近一直在忙着单位核心开发组件的版本更新,前天加了一个通宵,昨天晚上却睡不着,脑子里面突然不知怎的一直在想贪吃蛇的实现方法.以往也有类 ...
- 【java学习】Servlet简单的表单程序(一)
此文用于java学习,在此小记. 在此小Demo中使用到了Servlet,所以有必要了解一下Servlet的相关知识.(Servlet的相关知识摘抄自http://blog.csdn.net/jiuq ...
- JMS学习(四)-一个简单的聊天应用程序分析
一,介绍 本文介绍一个简单的聊天应用程序:生产者将消息发送到Topic上,然后由ActiveMQ将该消息Push给订阅了该Topic的消费者.示例程序来自于<JAVA 消息服务--第二版 Mar ...
- 搭建简单的CGI应用程序
原文来源于<核心编程3>第10章web编程 一.静态文件+脚本文件 1.首先开启cgiweb服务器 python2 -m CGIHTTPServer 8000 看到如下反应 2.服务器目录 ...
- 用Spring MVC开发简单的Web应用程序
1 工具与环境 借助Eclipse4.3 + Maven3.0.3构建Java Web应用程序.使用Maven内置的servlet 容器jetty,不需手工集成Web服务器到Eclipse.还帮我们自 ...
随机推荐
- jQuery:多个AJAX/JSON请求对应单个回调并行加载
因为我们使用jQuery,这意味着需要调用 jQuery.getScript 和 jQuery.getJSON 函数. 我知道这些函数都是异步执行(asyncronously)并且会延迟一段时间返回, ...
- Lintcode: Route Between Two Nodes in Graph
Given a directed graph, design an algorithm to find out whether there is a route between two nodes. ...
- Lintcode: Sort Colors II
Given an array of n objects with k different colors (numbered from 1 to k), sort them so that object ...
- Lintcode: Product of Array Exclude Itself
Given an integers array A. Define B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1], calculate B wi ...
- 最大权闭合图hdu3996
定义:最大权闭合图:是有向图的一个点集,且该点集的所有出边都指向该集合.即闭合图内任意点的集合也在改闭合图内,给每个点分配一个点权值Pu,最大权闭合图就是使闭合图的点权之和最大. 最小割建边方式:源点 ...
- ACM常用算法及练习(1)
ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...
- cell点击按钮崩的一种情况
这个错误表示:该类方法没有addBtnClick对应的方法: bug的复现:创建一个cell,并且添加一个类方法来赋值,在方法中,给按钮添加一个点击事件(addBtnClick),但是,再实现这个方法 ...
- Java基础(40):Java中的集合介绍---Collection与Map
集合类说明及区别Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMap ...
- asp上传图片提示 ADODB.Stream 错误 '800a0bbc'的解决方法
asp上传图片提示 ADODB.Stream 错误 '800a0bbc' 有这个提示有很多问题导致.权限是常见一种.这个不多说,还有一个有点怪的就是 windows2008显示系统时间的格式竟然是:2 ...
- 夺命雷公狗---Thinkphp----2之快快速搭建TP环境
<?php //定义项目目录 define('APP_PATH','./WEB/'); //开启调试 define('APP_DEBUG',True); //包含thinkphp项目入口文件 r ...