2009年12月10日 星期四

JXTA p2p 協定介紹之資料傳送

啟動 JXTA 網路後可以得到一個 net peer group 實例

infrastructurePeerGroup = jxtaNetMan.startNetwork();

而 net peer group 提供了許多 service ,透過其中的 discover service 及 pipe service
即可讓 peer 互相傳遞訊息。

// 取得 discovery service
discoveryService = infrastructurePeerGroup.getDiscoveryService();
// 取得 pipe service
pipeService = infrastructurePeerGroup.getPipeService();

第一個要了解的概念是 PipeAdvertisement ,Pipe 是 JXTA 用來進行 peer 與 peer 溝通
的通道,可以想像成 Socket ,實作上底層應該也是脫離不了 Socket,而傳輸
也是透過 InputStream 與 OutputStream 進行資料傳送。
而 Advertisement 是 JXTA 用來表示資源的定義文件,是一個規範好的 xml 文件
JXTA 為網路中的各式各樣的資源都有定義屬於他的 Advertisement 。
以 PipeAdvertisement 來說,就是用來表示某一個 Pipe 的 Ad 文件。

因此,在資訊傳送前,需先由接收端的 peer 建立一個 PipeAdvertisement ,並且,
綁定一個 InputPipe 到 PipeAdvertisement 上,再由 discovery service 發佈到 JXTA
網路上,而發送端的 peer 再由 discovery service 查詢到 PipeAdvertisement,並綁定
OutputPipe 到同一個 PipeAdvertisement 上,等到綁定完成後,即可開始傳送資料。

建立 PipeAdvertisement
PipeAdvertisement pipeAd = (PipeAdvertisement)
AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());
pipeAd.setPipeID(IDFactory.newPipeID(PeerGroupID.defaultNetPeerGroupID));
pipeAd.setType(PipeService.UnicastType);
pipeAd.setName("APIPENAME");

建立 InputPipe bind 到 pipe ad 並設定 listener

pipeService.createInputPipe(pipeAd, pipeMsgListener);

listener 是一個 PipeMsgListener 的介面的實例,當完成對方建立了 OutputPipe 並
開始傳送資料時,PipeMsgListener 的 方法:

public void pipeMsgEvent(PipeMsgEvent event)

而傳進來的 event 物件會收到傳送過來的資料。
隨後即可將 pipeAd 發佈到 discover service 上,並設定 life time 及 expiration time

discoveryService.publish(pipeAd, pipeAdLifetime, pipeAdExpiration);
discoveryService.remotePublish(pipeAd, pipeAdExpiration);

而另一個要發送資料的 peer 則必須先以 discovery service 查詢前一個 peer
發佈的 pipeAd

discoveryService.getRemoteAdvertisements(
null, // 指定單一查詢的 peer id,null 則表示查詢整個網路
DiscoveryService.ADV, // 查詢的 type
"Name", // 指定查詢項目
"APIPENAME", // 查詢項目的值
1, // 一次要找多少個 ad
null); // 指定 discovery listener

這樣即會送出一個查詢到 JXTA 網路,最後一項參數的 listener 也可以使用

discoveryService.addDiscoveryListener(disclistener);

disclistener 是一個 DiscoveryListener 介面的實例,當查詢 ad 有結果後會觸發
listener 的 :

public void discoveryEvent(DiscoveryEvent event)

並可以 event 裡取得 ad 物件。因此發送端 peer 就可以得到 pipeAd 了
得到 pipeAd 後,發送端需要先建立一個 OutPipe 並綁定到 pipeAd 上

pipeService.createOutputPipe(pipeAd, outListener);

outListener 是一個 OutputPipeListener 當 OutPipe 綁定完成後,會觸發 listener 的

public void outputPipeEvent(OutputPipeEvent event)

並由 event 取得 OutputPipe 實例,開始傳送資料。

因此總結來說,傳送端在觸發 OutputPipeEvent 後可以開始傳送資料,
而接收端在觸發了 PipeMsgEvent 後可以開始接收資料,至於建立資料的方法則是,
建立一個 net.jxta.endpoint.Message 實例:

Message msg = new Message();

Message 是資料的包裝,裡面可以包含多筆 net.jxta.endpoint.MessageElement 實例
以最單純的 StringMessageElement 舉例:

StringMessageElement sme = new StringMessageElement(
"elemName", // element 的 key
"elemValue", // element 的 value
null // signature
);

將 element 加入到 Message 中,並以 OutPipe 傳送

msg.addMessageElement("msgNameSpace", sme);
event.getOutputPipe().send(msg);

而接收端則由 PipeMsgEvent 取得 Message,並由 namespace 和 element key 取值

Message msg = event.getMessage();
ElementIterator itMsg = msg.getMessageElements("msgNameSpace", "elemName");
while(itMsg.hasNext()){
MessageElement msgElem = itMsgElem.next();
System.out.println(msgElem.toString()); // 印出 "elemValue"
}

沒有留言: