引言 管道的概念源於Unix
是不同線程之間直接傳輸數據的基本手段
JDK中java
io包中就有管道類
同時
管道在JXTA中是最基本的概念
是對等點之間的數據傳輸的主要方式
對等管道協議(PBP)明確規范了對等管道的綁定
解析
響應
本文依次剖析集中式(JDK)和對等環境下(JXTA)管道的實現方式
對比分析其異同
然後嘗試在JXTA中建立一個虛擬的全雙工的管道
本文的目標是通過對不同環境下管道的實現方式對比分析
來理解為什麼JXTA采用管道作為基本的數據傳輸手段
管道的形象化描述 一個生活中的情景
現在有兩個地區A
B
A是石油生產區
B是石油消費區
現在B地區需要消費A地區的石油
當然可以通過海運
空運獲得
然而最通常的方式是架設輸油管道
如圖所示
引言 管道的概念源於Unix
是不同線程之間直接傳輸數據的基本手段
JDK中java
io包中就有管道類
同時
管道在JXTA中是最基本的概念
是對等點之間的數據傳輸的主要方式
對等管道協議(PBP)明確規范了對等管道的綁定
解析
響應
本文依次剖析集中式(JDK)和對等環境下(JXTA)管道的實現方式
對比分析其異同
然後嘗試在JXTA中建立一個虛擬的全雙工的管道
本文的目標是通過對不同環境下管道的實現方式對比分析
來理解為什麼JXTA采用管道作為基本的數據傳輸手段
管道的形象化描述 一個生活中的情景
現在有兩個地區A
B
A是石油生產區
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中
A
B有一方能夠發現另一方的存在
A將數據發往B方
A發送數據與B接收數據是相互獨立的
現在回到問題的最初
為什麼要使用管道?A只管發送
B只管接受
那麼數據在哪兒呢?經過下面的分析
就會明白管道把管理數據緩沖區的重任交給了他自己
A
B均是圍繞這個緩沖區來啟停線程的
顯然這才是問題的本質
JDK中
類PipeInputStream(即前面所述的B)與PipeOutputStream(即前面所述的的A)可以很好的解決這一問題
首先給出類圖如下
下面是將類PipeOutputStream的connect方法代碼簡化後給予注釋
public synchronized void connect(PipedInputStream snk) throws IOException {
sink = snk; //將PipeInputStream的實例作為PipeOutputStream的一個屬性
以便調用
snk
in =
;//緩沖區的輸入位置
<
表示緩沖區為空
snk
out =
;//緩沖區的輸出位置
nnected = true;
}
連接以後
PipeOutputStream的write操作直接調用sink
receive(b);這樣
對緩沖區buffer的維護
就變成了read()和receive()操作之間的線程同步
JDK對緩沖區的處理非常巧妙
采用了循環列表
它用緩沖區的標志位的變化來代替數據的移動
類似於生活中的時鐘把線性的時間規范為
小時來表示
這不屬於本文的論述范圍
就不繼續分析了
read操作
正常情況下
從out位置讀取數據
緩沖區空時進入等待狀態
以輪詢的方式(
秒間隔)來自我釋放
receive操作
正常情況下
向in位置寫入數據
緩沖區滿時進入等待狀態
同樣
以輪詢的方式(
秒間隔)來自我釋放
JXTA對等管道的實現 通過對JDK的分析
我們可以了解到在集中式環境下
管道的架設方案是比較簡單的
在對等環境下(分布式環境下也類似)
出於同樣的目標
遇到的問題卻在急劇的擴大
例如
管道入口和出口之間如何相互發現?數據如何保證在不同的環境下傳送?甚至
對管道本身的概念發生質疑
一定是單入口
單出口嗎?
JXTA規范中
管道是在端點之上的服務或應用之間發送和接收信息的虛擬連接通道
管道提供在對等端點傳輸之上的網絡抽象
管道有點到點和廣播兩種通信模式
JXTA是通過管道廣告來唯一標示管道的
輸出管道要找到與其廣告相同的輸入管道才能發送數據
廣告內容如下
<!DOCTYPE jxta:PipeAdvertisement>
<jxta:PipeAdvertisement xmlns:jxta=
;>
<Id>
urn:jxta:uuid
A
E
AE
ABBE
EF
CBE
</Id>
<Type>
JxtaUnicast
</Type>
<Name>
PipeExample
</Name>
</jxta:PipeAdvertisement>
如果您需要對JXTA管道有實例化的概念
請參考Sing Li的使p
p能進行交互操作
Jxta命令shell
這篇文章有部分內容專門介紹了如何在通過shell使用管道
本文主要是從編程的視角去看管道是如何實現的
客戶視角
Project JXTA : Java Programmer
s 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獲得數據
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27397.html