最简单的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.还帮我们自 ...
随机推荐
- C# 模拟并发
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客! 当然,题外话说多了,咱进入正题! 在处理大数据的时候,经常会发生并发,并发的情况发生后,会出现数据污读,从而产生脏数据. 首 ...
- 数据块损坏(block corruption)
分为物理损坏和逻辑损坏-物理损坏一般指数据块头部不可以访问.数据块校验值不合法,数据块格式不再是oracle承认的格式-逻辑损坏一般是在物理性结构完整的情况下,数据的内容在含义上不正确,比如保存了不允 ...
- Java Thread线程控制
一.线程和进程 进程是处于运行中的程序,具有一定的独立能力,进程是系统进行资源分配和调度的一个独立单位. 进程特征: A.独立性:进程是系统中独立存在的实体,可以拥有自己独立的资源,每个进程都拥有自己 ...
- Canopy算法聚类
Canopy一般用在Kmeans之前的粗聚类.考虑到Kmeans在使用上必须要确定K的大小,而往往数据集预先不能确定K的值大小的,这样如果 K取的不合理会带来K均值的误差很大(也就是说K均值对噪声的抗 ...
- C++Primer 第十章
//1.标准库算法不仅可以应用于容器,还可以应用于内置数组,指针. //2.大多数算法都定义在头文件algorithm中.标准库还在头文件numeric中定义了一组数值泛型算法. //3.算法本身不会 ...
- G面经prepare: Straight Partition of A Deck of Cards
Define “Straight” as 5 cards with consecutive numbers. Determine if the deck can be fully divided in ...
- JavaScript----marquee滚动标签 图片无缝滚动 插入百度地图
页面的自动滚动效果,可由javascript来实现, 但是有一个html标签 - <marquee></marquee>可以实现多种滚动效果,无需js控制. 使用marquee ...
- poj: 1207
好吧这题竟然还有先大后小的可能,能不这么恶心下吗.. #include <iostream> #include <stdio.h> #include <string.h& ...
- linux第5天 socket api
IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件<netinet/in.h>中 通用地址结构用来指定与套接字关联的地址.以socka ...
- PAT乙级 1008. 数组元素循环右移问题 (20)
1008. 数组元素循环右移问题 (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 一个数组A中存有N(N>0)个整数,在不允 ...