P
P計算被Intel喻為第三代網絡革命的
點對點分散式網絡架構
JXTA是Sun旨在建立P
P通用技術基礎的計劃
定義了一組P
P協議
本文以一個簡單的聊天應用為例
介紹基於JXTA的P
P應用開發
概述
P
P即Peer
to
Peer
稱為對等連接或對等網絡
是一種點對點計算模式
JXTA是項目創始人
Sun首席科學家Bill Joy二十多年醞釀的結晶
JXTA技術是網絡編程和計算的平台
用以解決現代分布計算尤其是P
P計算中出現的問題
JXTA協議是一組為P
P網絡計算而設計的協議
共六種
這六種協議分別是
Peer Discovery Protocol
Peer Resolver Protocol
Peer Information Protocol
Peer Membership Protocol
Pipe Binding Protocol
以及Peer Endpoint Protocol
利用這些協議
我們可以讓消息跨越多個網絡
發送到網絡上的任意其他Peer
這些協議是所有Java P
P應用的基礎
請參見圖一的JXTA應用體系(該圖來自)
圖一
JXTA應用體系
本文的例子是一個基於JXTA的P
P應用
Peer可以利用它聊天
它允許Peer把自己注冊到網絡上
發送消息給其他Peer
或者從其他Peer接收消息
編寫JXTA應用要求JXTA內核以jxta
jar JAR文件的形成存在
(jxta
jar文件可以從下載
)jxta
jar文件必須在CLASSPATH中
構造JXTA應用並不是一件很復雜的事情
只需實現net
jxta
platform
Application接口
並提供該接口定義的三個方法
init()
startApp()和stopApp()
下面顯示的SimpleJXTA類就是一個最簡單的JXTA應用(注意
程序必須導入net
jxta
document
Advertisement類和net
jxta
peergroup
PeerGroup接口
init()方法需要它們)
// 最簡單的JXTA應用
import net
jxta
platform
Application;
import net
jxta
document
Advertisement;
import net
jxta
peergroup
PeerGroup;
public class SimpleJXTA implements Application {
public void init(PeerGroup group
Advertisement adv) {
}
public int startApp(String[] args) {
return
;
}
public void stopApp() {
}
}
作為一個Java應用
上面的程序是否遺漏了static void main()方法呢?其實
與普通Java應用相比
JXTA應用的運行方式有所不同
JXTA應用要求啟動JXTA平台
JXTA平台啟動之後
它將啟動所有在jxtaConfig配置文件中指定的應用
JXTA平台啟動一個應用時
首先調用應用的init()方法
接著調用startApp()方法
JXTA聊天程序
本文的聊天應用改編自JXTA Shell軟件包的Talk程序
設計這個應用的主要目的是為了學習JXTA編程
它很簡單
與基於Java Socket的許多聊天應用相比
它缺少許多高級特性
且不具備強健的錯誤控制機制
然而
這個程序用到了許多重要的JXTA類和接口
初學者可以由此開始深入了解JXTA
程序有一個很簡單的GUI
如圖二所示
圖二
程序界面
所有來自聊天用戶的消息
格式為
[用戶名字] 消息
聊天程序本身報告的信息都以
>
開頭
聊天程序的業務規則為
● 用戶在登錄文本框中輸入自己的名字
並點擊
登錄
按鈕登錄
● 用戶名字必須唯一
任何兩個用戶不能有相同的名字
如果某個用戶輸入的名字正在被其他用戶使用
則應用將報告該信息
正在試圖登錄的用戶必須改變自己的名字
● 成功登錄後
用戶在消息輸入框中輸入消息
所有消息將以廣播的形式發送給當前已經登錄的所有用戶
包括消息發送者本身
登錄
登錄的目的不是進行身份驗證
任何擁有聊天程序的人都可以加入聊天
登錄的目的是為了讓其他用戶知道當前用戶的存在
使得聊天程序能夠發送消息
或者從其他聊天用戶接收消息
消息通過管道從一個Peer傳遞到另一個Peer
管道由net
jxta
pipe包裡面的Pipe接口描述
管道是在兩個JXTA應用或服務之間傳遞消息的核心機制
它為兩個Peer之間的通信提供了簡單的
單向的
異步的通道
換句話說
管道把多個Peer終端連接到了一起
接收端稱為輸入管道
發送端稱為輸出管道
要讓輸出管道能夠把消息發送到接收管道
兩個管道首先必須互相認知對方
例如
聊天應用的一個實例能夠把消息發送給另一個實例之前
兩個實例必須互相認知對方
應用的一個實例必須把自己
介紹給
其他實例
這是如何完成的呢?
在JXTA術語中
讓其他Peer知道某個Peer已經在線叫做廣告(advertising)
從技術上看
advertising意味著把一個廣告發送給網絡上的所有用戶
這裡的廣告可以是任意網絡資源的標識符
可以用來描述各種核心對象
例如Peer
PeerGroup
Service
Pipe
Content或Endpoint
JXTA廣告是與平台無關的
一般以XML文檔的形式提供
在聊天程序中
由於管道是信息交換的核心對象
PipeAdvertisement代表著各個聊天用戶
PipeAdvertisement描述了一個管道通信通道
管道服務利用它創建關聯的輸入和輸出管道終端
當一個Peer發送它的廣告給另一個Peer
它可以期待另一個Peer的回應
即發回它的廣告
按照這種方式
雙方都將擁有對方的廣告
廣告由應用緩沖
以便以後使用
當應用需要廣播一個消息時會用到這些緩沖的廣告
JXTA自動在cm子目錄的特定目錄下
以文件的形式(文件名字唯一)緩沖廣告
對於本文的聊天應用
JXTA創建了一個名為e
d
b的目錄
在這個目錄下
有子目錄Adv
Groups
PeerInfo
Peers
private
public和tmp
如圖三所示
所有與聊天應用聯系的Peer的所有PipeAdvertisement都保存在Adv目錄下
包括聊天應用自己的PipeAdvertisement
educity
cn/img_
/
/
/
gif >
圖三
cm目錄結構
當一個用戶登錄
聊天應用首先檢查所有本地緩沖的PipeAdvertisement
如果其中一個緩沖的PipeAdvertisement的用戶名字與聊天用戶輸入的名字相同
則聊天應用將向用戶提示名字已經被使用
這種提示可能是錯誤的
因為以前使用該用戶名字的遠程用戶當時不一定登錄
另外
由於聊天應用緩沖了它自己的PipeAdvertisement
用戶不能在下一次會話中使用同一個名字
因此
如果必要
在啟動應用之前可以清除Adv目錄
當聊天應用搜索完所有本地緩沖的PipeAdvertisement
且不能找到匹配的用戶名字時
它將把搜索擴展到遠程用戶
如果用戶名字已經被某個遠程用戶使用
聊天應用將向試圖登錄的用戶提示該名字不可用
至此為止
聊天應用已經可以發送消息
為了接收消息
必須啟動執行監聽任務的線程
sendAll()方法提取所有本地緩沖的PipeAdvertisement
以用戶輸入的文字為基礎構造出一個消息
然後把消息發送給每一個PipeAdvertisement已經緩沖的遠程用戶
首先
sendAll()方法獲取發送者的用戶名字
接著
sendAll()方法調用getAllPipeAd()方法
獲取一個包含所有本地緩沖的PipeAdvertisement的Vector
然後
sendAll()方法利用循環依次訪問各個PipeAdvertisement
利用Pipe接口的createOutputPipe()方法構造一個OutputPipe對象
調用createOutputPipe()方法時傳入找到的PipeAdvertisement
如下所示
// 廣播廣告
int length = pipes
size();
for (int i =
; i<length; i++) {
PipeAdvertisement adv = (PipeAdvertisement) pipes
get(i);
OutputPipe pipeOut = null;
try {
//
這個值僅用於測試
// 可能需要等待更長時間
pipeOut = pipe
createOutputPipe(adv
Pipe
NonBlocking
);
} catch (Exception e) { }
如果成功地創建了OutputPipe對象
接下來開始構造Message對象
if (pipeOut != null) {
Message msg = null;
String userInput = null;
InputStream inputStream = null;
try {
// 構造一個消息
msg = pipe
createMessage();
Message對象的push()方法用來以InputStream的形式插入一組數據
因此
先把用戶消息(messageBox
getText())轉換成一個Byte數組
再轉換成ByteArrayInputStream
然後
把InputStream以參數的形式提供給push()方法
另外
我們還要在消息中加入發送者的名字
為此
先從sender字符串構造出另一個InputStream
再把它作為參數傳遞給push()方法
inputStream = new ByteArrayInputStream(
messageBox
getText()
getBytes());
msg
push(SENDER_TEXT
inputStream);
inputStream = new ByteArrayInputStream(sender
getBytes());
msg
push(SENDER_ID
inputStream);
准備好Message對象之後
把它作為參數傳遞給OutputPipe類的send()方法
把消息發送給接收的Peer
pipeOut
send(msg);
最後
關閉OutputPipe
pipeOut
close();
run()方法執行與sendAll()方法相反的操作
run()方法創建一個InputPipe
監聽傳入的消息
提取出Message對象的用戶名字和內容
並調用toDisplay()方法顯示出消息
首先
run()方法利用當前Pipe對象(pipe)的createInputPipe()方法創建一個InputPipe
如果createInputPipe()方法返回null
則顯示
不能打開InputPipe
錯誤信息
反之
如果成功地創建了InputPipe
run()方法開始一個無結束條件的while循環
監聽傳入的消息
如下所示
// 監聽傳入的消息
while
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27536.html