上篇博客 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法 实现了一个最简单的C/S程序,即让服务器来做加法。当时为了通俗易懂采用了消息异步调用的方式。今天我们要采用消息同步调用的方式来实现,并且对比一下两种方式的优劣。通过这个实例也能让对于“同步调用异步调用”不甚了了的朋友们对于这一对概念有一个初步直观的认识。
  究竟什么是消息同步调用什么是消息异步调用呢?

一·消息异步调用

  对于这个问题我们先不急于从原理上回答,先来看下上一次客户端向服务端发送消息的代码。
        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);
}

关键是客户端发消息的那句代码,发完消息后客户端就撒手不管了,究竟服务端有没有收到呢?会不会发出去的消息就是“肉包子打狗”呢?客户端不得而知。反正皮球踢给了服务端,好吧服务端接了,然后服务端是这样做的:

 //该方法用来处理客户端通过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);//发送给对应的客户端
}
}

服务端处理一番后再度发消息给客户端,又一个皮球踢了出去。客户端接球:

 //该方法来处理服务端Send()方法发送过来的消息
public void HandleInformation(string sourceUserID, int informationType, byte[] info)
{
if (informationType == )
{
MessageBox.Show("结果为:" + BitConverter.ToInt32(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];//第二个数的编码装进后四位
}
//发送给服务器请求获取结果
byte[] resultCode = Program.clientEngine.CustomizeOutter.Query(, NumbersCode);
int result = BitConverter.ToInt32(resultCode, );//解析
MessageBox.Show("结果为:" + result);
}

重点是发消息语句,与前面的“异步调用”的区别就在于请求返回结果,然而处理过程并不是在客户端的主机上完成的,而是在服务端:

   //该方法用来处理客户端发送过来的请求,即clientEngine.CustomizeOutter.Query()方法发送过来的消息
public byte[] HandleQuery(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);//将计算结果转码
return resultCode;
}
return null;
}

表面上类似于调用本地方法,但实质上是一个分布式处理过程。在服务端处理信息的过程中,客户端一直处于等待状态,直到服务端处理完毕返回结果。假使该语句下还有代码块,则在等待过程中不能够执行。这就是消息同步调用。

三·总结

消息同步调用与消息异步调用的概念脱胎于同步调用与异步调用的概念,相当于是对于原概念的拓展。同步调用与异步调用是对于方法的调用而言,所谓同步调用,就是在调用一个方法时,在没有得到结果之前,主调线程处在等待状态;所谓异步调用即,一个方法被调用后,主调线程不用等待结果返回。我们这里所谈的消息同步调用与消息异步调用是针对于“发送/回复”这种通信的逻辑模型而言,能够立即获得回复的发送称为消息同步调用,反之称为消息异步调用。

类似于方法同步调用,消息同步调用也会阻塞当前调用线程,但是由于其模型简单直观,而且将“发送“与”回复”严格匹配,在其适用的场合较消息异步调用模型具有优越性。

毫无疑问,在通信框架中,原始的模型就是异步调用模型,而ESFramework也增加了同步调用的机制,使得编程模型更加丰富。

至于消息同步调用与消息异步调用在实际的项目中如何运用来实现更复杂的需求,完成更强劲的功能,我会在该系列以后的博文中继续探讨,支持的朋友请顶一顶,给与我坚持不懈的力量!

四.源码下载

  让服务器做加法2--同步调用模型

循序渐进做项目系列(2):最简单的C/S程序——消息异步调用与消息同步调用的更多相关文章

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

    <循序渐进做项目系列迷你QQ篇>将陆续介绍客户端聊天,文件传输,加好友,群聊,包括语音聊天,视频聊天,远程桌面等等需求如何实现,感兴趣的朋友可以持续关注.考虑到某些需求较为复杂,本系列采用 ...

  2. 循序渐进做项目系列(4)迷你QQ篇(2)——视频聊天!(附源码)

    一·效果展示 源码派送:MiniQQ1.1 文字聊天的实现参见:循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天 二·服务端设计 对于实现视频聊天而言,服务端最核心的工作就是要构造多媒 ...

  3. 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法

    (本文是专门针对未接触过C/S开发的初学者而写的,C/S开发高手请自动忽略啊~~) 还在写“Hello world!”式的单机程序吗?还在各种拖控件吗?是否自己都觉得有点low呢?来个质的飞跃吧!看看 ...

  4. 循序渐进做项目系列(5):制作安装包,谁人都可以!——VS制作安装包简明教程

    一开始让我做安装包的时候,其实我是拒绝的.因为我根本就不会做安装包.查了资料之后,我很懵,很晕,很乱,因为不清晰,不简明,不直白.然而经过一番彷徨的挣扎,我终于发现:制作安装包,谁人都可以!故挥狼毫, ...

  5. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序使用异步及存储过程

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第九篇:为ASP.NET MVC应用程序 ...

  6. 套用GGTalk做项目的经验总结——GGTalk源码详解系列(一)

    坦白讲,我们公司其实没啥技术实力,之所以还能不断接到各种项目,全凭我们老板神通广大!要知道他每次的饭局上可都是些什么人物! 但是项目接下一大把,就凭咱哥儿几个的水平,想要独立自主.保质保量保期地一个个 ...

  7. 一步一步使用ABP框架搭建正式项目系列教程

    研究ABP框架好多天了,第一次看到这个框架的名称到现在已经很久了,但由于当时内功有限,看不太懂,所以就只是大概记住了ABP这个名字.最近几天,看到了园友@阳光铭睿的系列ABP教程,又点燃了我内心要研究 ...

  8. 一步一步使用ABP框架搭建正式项目系列教程之本地化详解

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 本篇目录 扯扯本地化 ABP中的本地化 小结 扯扯本地化 本节来说说本地化,也有叫国际化.全球化的,不管怎么个叫法,反正道理都是一 ...

  9. ABP框架搭建项目系列教程基础版完结篇

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...

随机推荐

  1. 自定义指令directive

    1.自定义指令 在angular中,module下面的directive方法用于创建自定义指令,用法: m1.directive('myTab',function(){ return { restri ...

  2. QT toLocal8Bit奇怪的问题

    #include "mainwindow.h" #include "ui_mainwindow.h" #include<QDebug> MainWi ...

  3. 6. Adapter Class/Object(适配器)

    意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性: 你想使用一个已经存在的类,而它的接口不符合你的需求. 你想 ...

  4. create()创建的控件不能映射消息函数的解决

    有时,使用create()在运行时创建的控件不能将消息映射到父窗口内,此时需要使用消息转发的机制,主要原理:注册一个全局的消息,针对接收消息的控件编写继承类,在该继承类中响应消息,并将已注册的全局消息 ...

  5. jsp中,个别乱码进行转码操作

    来自大神 if(xh!=null && xh!=""){ xhmc =new String(xh.getBytes("ISO-8859-1"), ...

  6. 《CODE》读后笔记——第1~13章

    1.电筒密谈 Morse code表 文中提到"英语词汇就是一种编码".这句话仿佛有一种哲学思想在里面,万物皆可以以任何形式编码,只是编码的方式和途径不同.有些编码简单易懂易于接受 ...

  7. 关于公司VPN专线接入的一个案例

    最近互通网络技术部门收到一到封邮件,是关于公司VPN接入的问题,问题如下: 条件:A区为办公地点1,其他办公电脑20台,并通过写字楼的宽带接口联通外网. B区为新办公地点2,预设应用.数据库.备份服务 ...

  8. ajax基础一

    AJAX AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJA ...

  9. 【转载】Adapter用法总结大全

    下面的是看到的比较好的地址: Android各种Adapter的用法:                 http://my.oschina.net/u/658933/blog/372151 Andro ...

  10. Spring中获取数据库表主键序列

    在程序开发中,我们经常有写数据库表的操作,数据表中经常带有主键自增序列,如何获取自增序列.spring中提供了相应的类 DataFieldMaxValueIncrementer. DataFieldM ...