循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法
(本文是专门针对未接触过C/S开发的初学者而写的,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();
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(, 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("", "", "127.0.0.1", , 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[];//用来合并待发送的消息(一个整型占4个字节)
for (int i = ; i < ; i++)
{
NumbersCode[i] = leftNumCode[i];//第一个数的编码装进前四位
}
for (int j = ; j < ; j++)
{
NumbersCode[j + ] = rightNumCode[j];//第二个数的编码装进后四位
}
//发送给服务器,100代表做加法这件事
Program.clientEngine.CustomizeOutter.Send(, 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 == )
{
int leftNum = BitConverter.ToInt32(info, );//将字节数组前四位还原成leftNum
int rigthNum = BitConverter.ToInt32(info, );//将字节数组后四位还原成rigthNum
int result = leftNum + rigthNum;
byte[] resultCode = BitConverter.GetBytes(result);//将计算结果转码
this.serverEngine.CustomizeController.Send(sourceUserID, , 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 == )
{
MessageBox.Show("结果为:" + BitConverter.ToInt32(info, ));
}
} public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info)
{
throw new NotImplementedException();
}
}
四·编译运行
1.先启动服务端,右击Server项目,调试,启动新实例
2.启动客户端
大功告成!
五·总结
虽然本文篇幅较长但是整个逻辑其实非常简单!之所以篇幅较长主要是因为花了较多的笔墨照顾初学者,同时也是因为尽力在营造循序渐进的逻辑过程,为了让每一步水到渠成,不突兀,不跳跃,惟其如此才是符合认识论的学习过程,同时也是我们实际编程中应该掌握的思维方式。
回头来看,其实所有的工作只分为两步:
1.引用通信框架并做好相关的准备工作,使得“如何实现通信”这一重要艰巨的问题刹那间迎刃而解!
2.编写相关的业务逻辑。
而1中的工作是超简单的,一回生二回熟,以后无论编任何C/S程序都是这个套路,从此我们只需要专注于具体的业务逻辑而不用理会关于底层通信技术的一切琐碎与繁难了!而这将大大提高工作效率!
援引邓小平同志的一句名言做结:“科学技术是第一生产力!”,也献给所有致力于成为IT精英的朋友!
循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法的更多相关文章
- 最简单的C/S程序——让服务器来做加法
还在写“Hello world!”式的单机程序吗?还在各种拖控件吗?是否自己都觉得有点low呢?来个质的飞跃吧!看看怎么让服务器帮咱做加法! 所谓C/S程序就是Client/Server程序,自然既包 ...
- 循序渐进做项目系列(2):最简单的C/S程序——消息异步调用与消息同步调用
上篇博客 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法 实现了一个最简单的C/S程序,即让服务器来做加法.当时为了通俗易懂采用了消息异步调用的方式.今天我们要采用消息同步调用的方式 ...
- 循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天
<循序渐进做项目系列迷你QQ篇>将陆续介绍客户端聊天,文件传输,加好友,群聊,包括语音聊天,视频聊天,远程桌面等等需求如何实现,感兴趣的朋友可以持续关注.考虑到某些需求较为复杂,本系列采用 ...
- 循序渐进做项目系列(4)迷你QQ篇(2)——视频聊天!(附源码)
一·效果展示 源码派送:MiniQQ1.1 文字聊天的实现参见:循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天 二·服务端设计 对于实现视频聊天而言,服务端最核心的工作就是要构造多媒 ...
- 循序渐进做项目系列(5):制作安装包,谁人都可以!——VS制作安装包简明教程
一开始让我做安装包的时候,其实我是拒绝的.因为我根本就不会做安装包.查了资料之后,我很懵,很晕,很乱,因为不清晰,不简明,不直白.然而经过一番彷徨的挣扎,我终于发现:制作安装包,谁人都可以!故挥狼毫, ...
- 一步一步使用ABP框架搭建正式项目系列教程
研究ABP框架好多天了,第一次看到这个框架的名称到现在已经很久了,但由于当时内功有限,看不太懂,所以就只是大概记住了ABP这个名字.最近几天,看到了园友@阳光铭睿的系列ABP教程,又点燃了我内心要研究 ...
- 一步一步使用ABP框架搭建正式项目系列教程之本地化详解
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 本篇目录 扯扯本地化 ABP中的本地化 小结 扯扯本地化 本节来说说本地化,也有叫国际化.全球化的,不管怎么个叫法,反正道理都是一 ...
- ABP框架搭建项目系列教程基础版完结篇
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...
- Laravel大型项目系列教程(一)
Laravel大型项目系列教程(一) 一.课程概述 1.课程介绍 本教程将使用Laravel完成一个多用户的博客系统,大概会包含如下内容: 路由管理. 用户管理,如用户注册.修改信息.锁定用户等. 文 ...
随机推荐
- ZOJ 3705 Applications 模拟
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include< ...
- IOS常见错误之一连线错误
在IOS编程中,UI方面,对于新手,接触时,不免喜欢拖控件,觉得省去了一些麻烦,其实在操作控件的过程中也有很多问题需要注意 本人今天就说下遇到的一个问题. setValue:forUndefinedK ...
- HttpWebRequest向路由器提交基本身份验证
HttpWebRequest向路由器提交基本身份验证 服务端IIS设置为不允许匿名访问,只选择了基本身份验证,客户端使用HttpWebRequest发送一个get请求,请求一个页面. 基本身份验证,客 ...
- 关于“float”的一次探索--遇到了一个span元素可以设置宽高引发的思考
起初,这个问题和float还有设置宽高之间是没有任何关联的,一开始这是一个关于height和line-height的问题,目的是为了探究一下这两者之间的关系,但是在学习的过程中,我翻之前写的代码,发现 ...
- Mysql监控、优化
一.查询语句的生命周期 1.MYSQL服务器监听3306端口 2.验证访问用户 3.创建MySQL线程 4.检查内存(Qcache),当查询命中缓存,MYSQL立刻返回结果,跳过解析.优化.执行阶段. ...
- 如何解决pycharm输入中文报错问题
在pycharm中的python文件中输入中文会报错SyntaxError: 问题解决方法在文件开头添加 : # -*- coding:utf-8 -*- 每次添加都很麻烦,一劳永逸解决此问题的方法: ...
- linux 项目环境搭建配置
经过三天加一上午的努力折腾,本地项目终于跑起来了,linux系统,重装后需要安装基本的php,nginx,mysql.php扩展需要安装curl ,memcache,memcached等.然后就是修改 ...
- XAMARIN +VS2015 ANDROID 开发禁止屏幕自动转动 Portrait,Nosensor
网上有很多java的写法,但是放在C#中都无法使用,其实有时候还是安下心来认真的去看官网文档比在百度或者google来的快的多 this.RequestedOrientation = Android. ...
- CSS clear清除浮动
1.CSS中的clear有四个参数: none:允许两边都可以浮动. left:不允许左边有浮动. right:不允许右边有浮动. both(默认):不允许有浮动. 2.一开始在CSS中clear浮动 ...
- 学习ES6--data2
变量的解构: let [a, b, c] = [1, 2, 3] 等号左边的值等于等号右边的值,一一对应.假如右边没有相对应的值,如 let [a, b, c] = [1, 2, ] 这时候,c = ...