大家都知道对于互联网的世界网络通讯是其本质特征。而对于一个分布式式计算来说更是如此。在它的环境中使用了客户/
服务器结构特点,使用的一个核心技术就是网络通讯层。在最早的OSI
的概念基础上,建立了完善具体协议层。而客户想要能够与位于其他物理层主机上的服务器通讯,需要能够想服务器发送数据,然后以某种方式获得响应。这当中就牵涉到我们熟悉的协议层面了,在这里就不再复述这些协议概念了。对于网络通讯来说我们所要了解的是最为常用的就是两种连接方式:无连接协议(UDP
)、面向连接协议(TCP/IP
)。
多数网络编程库中(以JAVA为主来说明),在JAVA平台中一样的提供了这些元素。而作为面向连接协议来说使用的是套接字(Socket)进行了更进一步的抽象描述。一般我们在JAVA的网络编程中都觉得在使用套接字这块相对方便,它不需要你去更多的了解操作系统的细节以及硬件的传递处理方式。TCP/IP的所有细节之处都得到了套接字的封装使用,让程序员关注到业务层面的处理。
对象是一种抽象思维物质,对于计算机来说它只对数字电路的存储方式能够加以识别而且在网络传输当中也是一种信号量,而这一切只有使用字节流方式传输才是真正需要做到的。所以在本地主机与远程服务器的通讯传输就在对象与字节流之间不断相互转化才是我们真正需要的人性物质与机器所需要的。(有点墨迹了,切入整体)总体来说就是需要两种方式来认定这种传输行为:编组(Marshalling)与反编组(Unmarshalling)。而这一切的手段方式才是通过:序列化(Serialiazable)与反序列化的方式不断完成。如下图所示:
图:对象到字节再到对象的转换
对于数据的传输本质就是上图说明的。那我们一般是如何使用套接字来构造我们这一行为呢?对于这里强调的主要是一种大致方法说明,所以只能以部分代码来说明客户端怎么来发送这个请求。
Socket socket=new Socket("http://www.wgh.com.cn",8888);
OutputStream out=socket.getOutputStream();
ObjectOutputStream obj=new ObjectOutputStream(out);
obj.writeObject(object);
InputStream in=socket.getInputStream();
ObjectInputStream objIn=new ObjectInputStream(in);
Object objFoo=(Object)objIn.readObject();
//todo 这里就是具体进行操作的相关传值参数处理了…
obj.close();
objIn.close();
socket.close();
而作为服务器的接收方则把以上数据做一个逆转相反处理就可以。即服务器需要读取发送过来的对象数据,最终得到结果。现在假设还是一个甚至更多这样的对象处理,我们又要处理和以上代码差不多的过程。好,到这里我们可曾想到难道没有一种办法把这些过多的重复过程做一个通用的方式来提供吗?我如果不想去做这些繁杂的对象处理可以吗?比如,我想直接得到:
//其中clientObjectji就是从客户端传输过来的副本;
MyObject myObject=server.getFoo(clientObject);
这样就能让我们把底层的那些庞杂数据转换能够透明封装起来呢?既然这个问题一经提出,那就意味着肯定有很多类似的需求。技术永远都是在需求的提出应运而生的。上面提出的需求就是我们要讨论的,既然我们想把一些套接字的重复处理过程来个封装清理,那需要面对的问题是什么呢?
1. 能够把所有的相同处理过程全部都移入到服务端呢?
2. 对于客户端来说能否只预留接口行为呢?
3. 把过多的复杂处理过程完善的做个封装?
4. 如果以上过程能够形成,那客户端又是如何办到可以连接到服务器端的组件行为呢?
既然能够把遇到的问题提出然后总结出来也就意味着我们需要去解决它。不知道是否还
记得设计模式中有一个叫:代理模式?没错,就是这个代理模式开始我们的描述。代理是一个实现给定接口的对象,但是不直接去执行代码结果,而是代表其他一些对象执行实际计算的对象。怎么理解这个话呢?举例说,如今很多城市都有火车票或者飞机票的代售点,这里的代售点其实就是采用了一种代理机制。我们想买某天的火车或者飞机票有时候并不需要到火车站或者飞机票的总点去购买票,而是找一个你最近的代售点去购买。代售点就是起到一个中间桥梁的作用,至于买票人员无需关心他们如何去订购,这些具体的动作都由他们内部去处理,你只关心最终是否有你需要的票就行。知道这个原理接下来就好理解很多了,我们最好以类图的方式来说明这个代理的机制,如图所示:
到这里如果还觉得抽象,没关系接下来我以更加贴切的实例来结合类图的方式给出对应的参照说明。假如我们把上面的proxy模式再做个深入的探讨剖析(结合上面说的客户端发送参数作为请求和提出的问题综述)。大家都知道一个接口是能够在安全甚至在扩展上能够帮助我们非常大的功能。作为客户端最为希望的就是只关心我们需要的参数(或者变量)、返回值,而它如何而来,做了哪些具体工作这些都不是客户端关心的。Ok,现在结合我们说的接口方式,确实可以解决这个问题(接口的简单化,没有具体实现),但是你可能会问:
1. 既然接口如此简单,那参数又是如何传递过去的呢?
2. 服务端又如何知道我要的是什么呢?
带着问题我们来解决这个问题,当然也是大家所关心的问题了。现在开始要对于上面的proxy模式做个深入剖析了。我们先来看一个proxy模式演变的过程的图示:
图:RMI核心结构
我们可以从图示看出从传统的proxy模式变化到一个变化的结构有什么不同呢?对于先前我们提出的两个问题就可以很好的做出解释了:
n 既然接口如此简单,那参数又是如何传递过去的呢?
A:既然是对客户端只开接口暴露,那么我们是就需要一个后台的socket来传输接口中已经定义好的参数,通过参数的编组(序列化)方式请求到远程服务上去响应处理。这当中要求定义到对方服务的服务名称和端口号。(这里也就是我们最先提到的那段代码了)
n 服务端又如何知道我要的是什么呢?
A:ok,既然客户端是通过socket来发送数据,那势必一定需要ServerSocket来做这个响应的接收处理了。问题是传过来的参数如何与我们的业务实现类关联上呢?所以这个也就是skeleton的职责所在了,在skeleton的封装处理中(启动中就把响应实现类给嵌入,聚合实现类),然后通过类转换处理和匹配处理来得到需要响应的结果了。
本来说到这想大概有个收尾,但是总觉得还没有把一些问题说透彻。索性想再深入写写。
从套接字衍生到RMI代码思路
posted on 2009-02-02 11:57
叶澍成 阅读(3570)
评论(1) 编辑 收藏 所属分类:
java基础 、
分布式