循序渐进做项目系列:最简单的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();
            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.启动客户端

大功告成!

源码下载:CSAdd.zip

五·总结

虽然本文篇幅较长但是整个逻辑其实非常简单!之所以篇幅较长主要是因为花了较多的笔墨照顾初学者,同时也是因为尽力在营造循序渐进的逻辑过程,为了让每一步水到渠成,不突兀,不跳跃,惟其如此才是符合认识论的学习过程,同时也是我们实际编程中应该掌握的思维方式。

回头来看,其实所有的工作只分为两步:

  1.引用通信框架并做好相关的准备工作,使得“如何实现通信”这一重要艰巨的问题刹那间迎刃而解!

      2.编写相关的业务逻辑。

而1中的工作是超简单的,一回生二回熟,以后无论编任何C/S程序都是这个套路,从此我们只需要专注于具体的业务逻辑而不用理会关于底层通信技术的一切琐碎与繁难了!而这将大大提高工作效率!

援引邓小平同志的一句名言做结:“科学技术是第一生产力!”,也献给所有致力于成为IT精英的朋友!

时间: 2025-01-15 22:18:00

循序渐进做项目系列:最简单的C/S程序——让服务器来做加法的相关文章

循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天

<循序渐进做项目系列迷你QQ篇>将陆续介绍客户端聊天,文件传输,加好友,群聊,包括语音聊天,视频聊天,远程桌面等等需求如何实现,感兴趣的朋友可以持续关注.考虑到某些需求较为复杂,本系列采用成熟的通信框架ESFramework来做,而不是从socket做起,当然这与本人才疏学浅也有莫大的关系,如果大家不嫌弃小弟写得太“low”,还请捧个人场,顺便给予鼓励! 言归正传,今天就是要实现一个最简单的功能:客户端互相聊天. 一·部署通信设备 参见 循序渐进做项目系列(1):最简单的C/S程序——让服务器

刚做完几个简单的响应式设计的网站项目下来,杂七杂八 (一)

之前没接触过responsive design这玩意,突然最近客户的项目都要求要有响应式设计的要求: 1,当浏览器缩放时,页面要根据浏览器大小,而自动适应. 2,当用手机或者移动设备打开页面时,页面会根据屏幕浏览器的大小自动适应. 3,移动设备有横屏和竖屏之分,页面也要相应适应 首页设计 UI设计师只设计出了2种mockup,一种是full site一种是mobile site然后扔过来,一看那mockup就知道是当前比较流行的设计风格. 1,页头head,左logo右菜单:在full site

做项目时需要考虑的安全性问题

在开发一个项目的时候,大家经常会忽略项目的安全性问题,有很多的安全性问题其实就是一个意识的问题,解决起来并不复杂,但是因为这些疏忽,却可能会给我们的用户带来很大的风险.下面就列举一些在做项目的时候应该考虑的一些安全性问题. 密码保存 保存密码的第一准则是不能明文保存密码,之前CSDN密码泄露一事还记忆犹新.通常的做法是对密码进行不可逆加密,加密时不要使用MD5或者SHA系列的算法加密,现在对这两个算法的破解研究工作已经有了相当的进展.推荐使用bcrypt. CI服务器的安全性 CI服务器和Bui

【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目 (13)客户管理

声明:本系列为原创,分享本人现用框架,未经本人同意,禁止转载!http://yuangang.cnblogs.com 希望大家好好一步一步做,所有的技术和项目,都毫无保留的提供,希望大家能自己跟着做一套,还有,请大家放心,只要大家喜欢,有人需要,绝对不会烂尾,我会坚持写完~ 如果你感觉文章有帮助,点一下推荐,让更多的朋友参与进来,也是对本人劳动成果的鼓励,谢谢大家!由于还要工作,所以基本都是牺牲午休时间来写博客的,写博客呢不是简单的Ctrl+C.Ctrl+V,我是要挨着做一遍的,这也是对大家负责

谈谈最近独立做项目的一些事情,一些小经验,分享之!

可以说我是一个码农,一个纯正的码农,一个脱离了低级趣味的码农,时刻准备着要做一个对社会有贡献的码农. 平常最喜欢的事情就是在群里问问题,总是有那么一群好哥们在一起,这样可以享受装逼的乐趣. 谈了这么多无厘头的话题,总归要切入正题,我大学的时候学的是JAVA,但是无奈大学时光都沉浸于美色和游戏当中,所以导致大学毕业的时候,只会写一点简单的东西,只知道JAVA中的swing(这个貌似是我懂的最深的知识了). 也就是在我找工作四处碰壁,走投无路的时候,我发现了一条阳关道:啃老.虽然这不怎么好,但是确实

在大学里做项目

我想计算机专业的学生一般都希望自己变得很NB,最好想实现什么功能就实现什么功能.对于在上大学前没计算机功底的低年级学生,有朝一日做做项目什么的也是个美丽而羞涩的梦. 当一个人通过一两年老老实实的学习,有了编程基础后,总希望老师给个课题来.没老师的"鼓励",一般学生是不会自己找项目做的,而事实是老师不会随便给课题,大多自己想去.只有很牛叉学校的学生才有机会自己出差谈业务.就算有什么idea想实现,没什么经验的student也总想拉帮结派合成"项目组".也许人多心里踏实

从0开始,一起搭框架、做项目(3)公共基础数据操作类 RepositoryBase

索引 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目 目录索引 简述 今天我们写一个基础数据的操作类,如果里面有大家不理解的地方,可采取两种方式,第一:提出来,第二:会用就行.这个类呢我一般不去修改它,因为基础操作类,大家也可以直接拷贝到自己的项目中. 项目准备 我们用的工具是:VS 2013 + SqlServer 2012 + IIS7.5 希望大家对ASP.NET MVC有一个初步的理解,理论性的东西我们不做过多解释,有些地方不理解也没关系,会用就行了,用的多

【转】做产品VS做项目

相关定义 根据GB/T19000—2008<质量管理体系基础和术语>,有以下定义 过程process 一组将输入转化为输出的相互关联或相互作用的活动 注:一个过程的输入通常是其他过程的输出.   产品product 过程的结果 注:产品可以是有型的,比如汽车,也可以是无形的,比如培训.咨询服务.   项目project 由一组有起止日期的.协调和受控的活动组成的独特过程,该过程要达到符合包括时间.成本和资源约束条件在内的规定要求的目标 注: 1,单个项目可作为一个较大项目的组成部分. 2,项目

是不是应该坚持跟老师做项目

[来信] 贺老师你好:  希望老师能在百忙之中,看看这封来信?  贺老师,你好,我现在是一名大三的学生,在大二的时候就开始关注你的博文了,看了相关的文章并结合自己的亲身经历在不断的思考总结  不曾想过会给你发邮件,但随着毕业季的到来,越是觉得怀疑自己是否应该坚持自己的道路. 简单的介绍下自己吧,我在一所普通的211大学,学习的是通信专业,由于我们学校的特殊制度,大二才算分专业,真正的努力也从大二开始,成绩还算可以,能保持在年级前10.在寒假学习过单片机,用它完成过我们的一些课程项目,后来机缘巧合