原文:http://blog.sina.com.cn/s/blog_6203dcd60100y2gd.htmlhtml
【第十二阶段 :传输协议、接口、远程调用】编程
这一部分主要谈谈关于协议、接口和远程调用相关的内容。原本这一部分应该在以前就有比较详细的讨论,不过我放到后面来,足见其重要性。特别是在系统愈来愈多的时候,这几个东东直接决定了咱们的开发速度和运维成本。服务器
好,接下来咱们一个个的看。网络
1、传输协议负载均衡
到目前为止,在不一样系统之间获取数据的时候,你是采用那种方式呢?框架
咱们简单看一个例子:运维
以上这个多是咱们最(|两万字的分隔线|)初学习网络编程的时候,最常使用的一种C-S交互方式。其实这里面咱们已经定义了一种交互协议,只是这种方式显得比较山寨,没有规范。扩充性等等都没有充分考虑。异步
咱们在学习网络编程的时候,老师就给咱们讲过,网络分层的概念,经典的有5层和7层模型。在每一层里面,都有本身的协议。好比:IP协议、TCP协议、HTTP协议等等。这些协议基本上都由两部分组成:头+数据。函数
【头信息】工具
咱们来看看TCP协议:
(注:以上是我从百度百科上截取的)
头信息中,通常可能会包含几个重要的元素:协议标识符、版本号、串号(或是本次交互的id)、数据包长度、数据校验等信息,可能有些协议还会带一些其余数据,好比数据发出方名称、接收方名称、时间、保留字段等等信息。
这些信息的目的,就是为了清晰的表达,我是怎么样的一个协议,我有哪些特征,我带的数据有多大。方便接收方可以清晰的辨认出来。
【数据部分】
数据部分是为了让应用层更好的通信和表达数据。要达到的目标就是简洁高效、清晰明了。提及来很容易,可是实现起来要考虑的东西就比较多,好比:数据压缩、字符转移、二进制数据表达等等。
咱们一般有多种格式来做为数据部分的协议。大致上能够分为:
A、二进制流。好比:C里面的结构体、JAVA里面的Serializable,以及像Google的protobuf等。将内存里面实体的数据,按字节序列化到缓冲区。这种方式的好处就是数据很是紧凑,几乎没有什么浪费。可是,问题也比较明显。双方必须很清楚协议,面向的语言基本上是要求同样的,很难作兼容,跨平台差。且扩展性比较差。另外,还有网络大小端字节序(Big-Endian、Little-Endian)的问题须要考虑。
B、文本传输协议。就是以字符串的方式来组织信息。常见的有XML、JSON等等。这种方式的好处就是扩展性强,跨平台兼容能力好,接口标准且规范。问题就是传输量比较大,须要考虑作压缩或者优化。
XML方式:
JSON方式:
所以,咱们能够按照咱们实际的需求,来定制咱们想要的数据格式,从而达到高效和易于表达和扩展的效果。
通过上述分析,咱们基本上对传输协议有了一个比较大体的了解。有了传输协议以后,咱们的跨机器间的数据交互,才显得比较规范和具备扩展性。若是咱们还不想本身来定义协议,咱们能够用现有的协议进行组合,好比:HTTP+XML、HTTPS+JSON等等。只要在一个平台上,你们都遵照这样的规范,后续开发起来就变得轻松容易。
2、接口(或者API)
接口是咱们的服务对外表达的窗口。接口的好坏直接决定了咱们服务的可表达性。所以,接口是一个承上启下的做用。对外,很好的表达提供的服务名称、参数、功能、返回的数据等;对内,可以自动生成描述所对应的代码函数框架,让开发者编写实现。
咱们描述咱们接口的方式有不少,能够利用描述性语言来表达。好比:XML、JAVA里提供的IDL(Interface Definition Language)等等。咱们把这种描述接口的语言统一称为IDL(Interface Definition Language)。
咱们能够本身开发一些工具,将IDL进行翻译,转换成方便阅读的HTML格式、DOC、CHM等等。方便其余开发者查阅。
同时,另一方面,咱们能够将IDL转换成咱们的接口代码,让服务接口的开发者和调用方的开发者按规范和标准来实现。
对于下层代码如何来实现数据的解析、函数的调用、参数的传递、数据的转换和压缩、数据的交换等等工做,则由工具来生成。对上彻底屏蔽。详细的内容,咱们将在接下来的远程调用中来分析。
3、远程调用
咱们最初写代码的时候,就被教授了函数的概念。咱们能够将一些公用的代码,或者实现必定含义或逻辑的代码,作成一个函数,方便重复的使用。
最开始,这些函数每每在同一个文件里,咱们只要先申明,便可使用。
后来,咱们开始使用库里面的函数,或是将函数封装成一个个的库(好比C里面的静态库.a或者动态库.so,或者是Java里面的.jar)。
以上对于函数的调用,以及函数自身的处理都是在本地。假如,当咱们单机不能知足需求的时候,咱们就须要将函数的处理放到其余机器上,让机器作到并行的计算。这个时候,咱们就须要远程的函数调用,或者叫作远程过程调用(Remote Procedure Call 或者 Remote Method Invoke,简称RPC或者RMI)。
咱们在这以前讲过几个东东:负载均衡、命名位置服务、协议、接口。其实前面讲这几个东东都是为了给远程过程调用作铺垫。RPC都是创建在以上部分的基础上。
仍是按照咱们以前分析问题的思路:为何要这个东东?这个东西解决什么问题?如何实现?有哪些问题?等等来分析RPC吧。
RPC的目的,就是使得从不一样服务上获取数据如同本地调用同样方便和天然。让程序调用者不须要了解网络细节,不用了解协议细节,不用了解服务的机器状态细节等等。若是没有RPC,其实也是能够的,就是咱们写程序的时候难受点而已,哈哈。
接下来,咱们看看如何来实现。
以上是整个的一个大致静态逻辑。最早编写调用的IDL,完成后由工具生成接口说明文档(doc);同时,生成客户端调用代码(stub,咱们叫作存根);另外,须要生成server端接口框架(skeleton),接口开发者实现具体的代码逻辑。
以上就是客户端调用的整个逻辑。
(今天先写到这里,明天要上班,须要早睡。PS:泰坦尼克3D还真不错,我以为主要缘由不是由于3D效果,而是重温没法超越的经典!)
(好,继续昨天的话题。)
客户端的使用很是简单,利用工具生成的库或者代码(推荐是库的方式,便于维护和升级),编译进代码或者运行时动态加载均可以。调用时直接使用函数调用方式便可。
而在库里,整个流程如上图:
A、先根据服务名称,从命名位置服务上获取服务信息,包括机器列表、端口、协议类型等等;
B、而后将传入参数和调用函数等信息按协议打包;
C、以后利用链接池和负载均衡策略,从中选取可用的链接,发送数据给服务器。
D、这个时候,若是咱们使用的是同步模式,咱们就等待数据返回。若是是异步模式,就直接先返回,等有数据回来后,再调用回调函数。
E、当数据回来后,咱们将数据按协议解包,并拼装成对应的类或结构体,返回给调用者。
整个客户端的调用过程对调用者是透明的,看起来就跟本地调用同样。调用者不用关心个人机器在哪里,用的哪一个端口,用的什么协议,数据应该怎么组装等等。全部的一切,都已经作好,看起来是那么的完美和简单!
再来看看server端的流程。
server端的处理逻辑就比较简单,跟据参数来分发不一样的请求,处理完成后,就打包返回数据便可。开发者要实现的就是红色部分。其余均有代码框架生成。
好了,咱们再回过头来看看,整个远程过程调用,
目标:让系统间的耦合尽量降到最低;简化开发,提高开发效率。
方法:利用了命名位置服务、负载均衡、网络交互协议、程序交互接口等工具
效果:使得开发远程数据获取和本地调用同样简单有效,不用关系底层细节。
固然,在咱们实际作的过程当中可能会遇到不少问题,好比:如何考虑跨平台的实现?如何考虑扩展性?如何来管理链接池等等。不过这些问题只要考虑到了,都是能够解决的。
在业界,其实也有不少成熟的系统,好比Microsoft的COM/DCOM、OMG的CORBA、SUN的EJB等等。因此远程过程调用其实都是比较成熟和现成的东东。不过要把他作好,真的是不容易,要考虑的东西太多。若是真能作好,整个系统就完美了!