引言
管道的概念源于Unix是不同线程之间直接传输数据的基本手段JDK中javaio包中就有管道类同时管道在JXTA中是最基本的概念是对等点之间的数据传输的主要方式对等管道协议(PBP)明确规范了对等管道的绑定解析响应
本文依次剖析集中式(JDK)和对等环境下(JXTA)管道的实现方式对比分析其异同然后尝试在JXTA中建立一个虚拟的全双工的管道
本文的目标是通过对不同环境下管道的实现方式对比分析来理解为什么JXTA采用管道作为基本的数据传输手段
管道的形象化描述
一个生活中的情景现在有两个地区ABA是石油生产区B是石油消费区现在B地区需要消费A地区的石油当然可以通过海运空运获得然而最通常的方式是架设输油管道如图所示
引言
管道的概念源于Unix是不同线程之间直接传输数据的基本手段JDK中javaio包中就有管道类同时管道在JXTA中是最基本的概念是对等点之间的数据传输的主要方式对等管道协议(PBP)明确规范了对等管道的绑定解析响应
本文依次剖析集中式(JDK)和对等环境下(JXTA)管道的实现方式对比分析其异同然后尝试在JXTA中建立一个虚拟的全双工的管道
本文的目标是通过对不同环境下管道的实现方式对比分析来理解为什么JXTA采用管道作为基本的数据传输手段
管道的形象化描述
一个生活中的情景现在有两个地区ABA是石油生产区B是石油消费区现在B地区需要消费A地区的石油当然可以通过海运空运获得然而最通常的方式是架设输油管道如图所示
java中流的概念和管道的概念都可以通过此案例阐述A与B之间连接的就是管道负责将A的石油向B输出A向管道输出数据(output)B从管道输入数据(input)可以这样理解管道是A的输出对象是B的数据源这里就产生了三个类输出流A输入流B管道输入流B负责如何获取数据(read 操作)输出流A负责如何消费数据(write操作)管道负责连接它们(connect 操作)其实在实现时管道类分解为管道口管道出口由入口出口负责连接在复杂的网络环境中这种连接方式可以有专门的网络协议负责(例如JXTA中的PBP全称Pipe Bind Protocol)
由以上描述我们可以清楚知道最原始的管道就是单向的文章后面介绍的双向管道是用两个单向管道虚拟的而非真实的连接方式不难发现管道最关键的问题是如何协调输出(A)与输入(B)这在不同的网络环境会遇到不同的问题最简单的是同一JVM下的不同过程(线程或任务)之间用同步方式传递数据而对等环境下如何去发现对方就是一个很现实的问题这仅仅只是问题的其中之一下面的章节会依次分析
集中式环境下管道的实现
问题的描述A与B是在同一JVM中AB有一方能够发现另一方的存在A将数据发往B方A发送数据与B接收数据是相互独立的
现在回到问题的最初为什么要使用管道?A只管发送B只管接受那么数据在哪儿呢?经过下面的分析就会明白管道把管理数据缓沖区的重任交给了他自己AB均是围绕这个缓沖区来启停线程的显然这才是问题的本质
JDK中类PipeInputStream(即前面所述的B)与PipeOutputStream(即前面所述的的A)可以很好的解决这一问题首先给出类图如下
下面是将类PipeOutputStream的connect方法代码简化后给予注释
public synchronized void connect(PipedInputStream snk) throws IOException {
sink = snk; //将PipeInputStream的实例作为PipeOutputStream的一个属性以便调用
snkin = ;//缓沖区的输入位置<表示缓沖区为空
snkout = ;//缓沖区的输出位置
nnected = true;
}
连接以后PipeOutputStream的write操作直接调用sinkreceive(b);这样对缓沖区buffer的维护就变成了read()和receive()操作之间的线程同步JDK对缓沖区的处理非常巧妙采用了循环列表它用缓沖区的标志位的变化来代替数据的移动类似于生活中的时钟把线性的时间规范为小时来表示这不属于本文的论述范围就不继续分析了
read操作正常情况下从out位置读取数据缓沖区空时进入等待状态以轮询的方式(秒间隔)来自我释放
receive操作正常情况下向in位置写入数据缓沖区满时进入等待状态同样以轮询的方式(秒间隔)来自我释放
JXTA对等管道的实现
通过对JDK的分析我们可以了解到在集中式环境下管道的架设方案是比较简单的在对等环境下(分布式环境下也类似)出于同样的目标遇到的问题却在急剧的扩大例如管道入口和出口之间如何相互发现?数据如何保证在不同的环境下传送?甚至对管道本身的概念发生质疑一定是单入口单出口吗?
JXTA规范中管道是在端点之上的服务或应用之间发送和接收信息的虚拟连接通道管道提供在对等端点传输之上的网络抽象管道有点到点和广播两种通信模式
JXTA是通过管道广告来唯一标示管道的输出管道要找到与其广告相同的输入管道才能发送数据广告内容如下
<!DOCTYPE jxta:PipeAdvertisement>
<jxta:PipeAdvertisement xmlns:jxta=;>
<Id>
urn:jxta:uuidAEAEABBEEFCBE
</Id>
<Type>
JxtaUnicast
</Type>
<Name>
PipeExample
</Name>
</jxta:PipeAdvertisement>
如果您需要对JXTA管道有实例化的概念请参考Sing Li的使pp能进行交互操作Jxta命令shell 这篇文章有部分内容专门介绍了如何在通过shell使用管道本文主要是从编程的视角去看管道是如何实现的
客户视角
Project JXTA : Java Programmers Guide Chapter有个例子阐述如何去在对等点之间发送信息读者可以到下载源码现在从客户视角简要的分析它的传送原理要深入的了解可以看下一节的系统视角分析
该例中有两个对等点并且构建了两个不同的类一个负责接收(Pipelistener)一个负责发送(PipeExample)具体的接收次序可以参考时序图
educitycn/img_///gif>类Pipelistener实现了接口PipeMsgListener类PipeExample实现了接口OutputPipeListener
由时序图(这是两个JVM中的类所以时序符号是独立标示的)可以清晰的获知各个对等点的前步是相互独立的各自的第步采用回调的方式建立输入和输出管道一旦对等系统探测到对方的存在就分别触发各自的事件发送或接收消息显然JXTA中管道是异步的
调试该例程时注意先建立输入管道然后建立输出管道因为输出管道在一定的时间和次数内探测不到输入管道的存在就会主动放弃否则容易让网络系统在这些无休止的探测中瘫痪
系统视角
从上面的例程中可以了解对等管道的创建方法以及数据流程但是不能明确对等系统是如何去实现的JXTA中管道的实现比在JDK中实现要复杂得多具体的技术标准可以参考对等管道绑定协议(PBP)此协议规范了JXTA中管道的概念但并没有涉及到如何去实现这同样是所有JXTA协议的特征它们的目标是阐述what it is而把how to do it留给开发者这样有利于增强系统的开放性其中Java参考实现就是该协议实现的一个案例以下将具体分析
首先看管道实现的类图(以单播为例)
educitycn/img_///gif>关键的类
InputPipeImpl 输入管道的实现类
NonBlockingOutputPipe 输出管道的实现类
PipeServiceImpl 管道服务的实现类负责创建输入输出管道
PipeResolver 提供管道绑定的解析服务
通过客户视角的分析可以得知系统外部是通过PipeServiceImpl来获取输入输出管道那么消息是如何在对等系统中通过管道过滤和传递的? 从程序实现的角度涉及到太多的技术细节JXTA的参考实现中有着庞杂的监听系统本文尝试用一个案例从两个层次去解析这个问题两个层次分别是消息的具体形式服务和端点协议的具体分发策略很显然这里我们把注意力放在了管道的架构路径上而把如何去架构放在了一边我想它们是有先后关系的并且距离并不遥远
案例描述
现在假设有两个对等点alas 和sisal 在一个局域网内按照客户视角那一节的例程sisal先建立输入管道alas建立输出管道由于同一网内可以用广播的方式发送查询信息可以不设rendevous并且路由是两点间的消息传递过程得到了一定的简化
案例分析
以上案例中从输入输出管道的建立到完成对接并传输数据总共有个步骤
sisal建立输入管道
alasl建立输出管道需要查找输入管道通过广播向网络发出管道查询消息
sisal获得alas的管道查询消息通过单播向sisal发出响应表示
alas获得sisal的响应通过单播向alas发出数据
sisal获得数据