摘要:利用Windows Vista的增強功能并結合PNRP(對等名稱解析協議)、PNM(People Near Me)和WCF(WindowsCommunication Foundation)中引進的PeerChannel功能,解決了傳統的P2P應用程序開發中的常見問題。
關鍵詞:對等名稱解析協議;PNM;WCF;PeerChannel
0引言
從傳統意義來說,P2P應用程序開發所面臨的難題包括:需要開發用于消息交換的專用協議;必須查找并連接隱藏在“網絡地址轉換”(NAT)或防火墻背后的應用程序實例;需要支持在廣域網(WAN)中定位各應用程序所需的慣常基礎結構。這些問題將隨著Windows Vista和.NET Framework的發布而得到解決。將Windows Vista的增強功能與PNRP、PNM和WCF中引進的PeerChannel功能相結合,就能順利開發P2P應用程序。
1 P2P基本原理:網格計算
網格計算是利用互聯網技術,把分散在不同地理位置的計算機組成一臺虛擬超級計算機,其中每臺計算機是一個“節點”,所有計算機就組成了節點網——網格。節點加入網格的方式取決于所使用的網格技術,通常,該節點必須用網格名來解析網格中已有的一個或多個節點的物理地址。在接收到網格中一個或多個節點的物理地址后,預期節點必須立即連接到這些地址中的一個、部分或全部地址,并應該準備好響應后續的其他預期節點的網格名解析請求。網格名解析是一個復雜的問題。這是因為,在許多情況下,網格名解析要依賴于一個或更多的其他網格。
節點連接到網格,它就可以通過以下兩種方式之一與其他節點進行通信:網格擴散(也稱多方消息傳送),或定向消息傳送。網格很少處于靜態。在多數P2P應用程序中,由于網絡連接變動,或者是用戶啟動和終止應用程序,節點可能會頻繁地加入和離開網格。多數網格都具備一些維護機制。通常而言,網格維護的目標就是修復或調整網格以使其更高效或更穩健地運行;各種網格技術實現網格維護的方式都不同。
2 PNRP(對等名稱解析協議)
PNRP完成網格名向物理地址的轉變。PNRP v1可供Windows XP(SPl)以上版本使用。可以說,PNRP本身就是一個采用Windows服務形式的P2P應用程序,并且PNRP節點的網格專用于發現加入到其他網格中的節點的物理地址。
PNRP和1Pv6 PNRP構建于Internet協議版本IPv6之上。PNRP功能的原型、結構、錯誤代碼均在Windows SDK的p2p.h頭文件中定義。如果某應用程序想要向PNRP注冊—個網格名,它必須用非托管代碼通過Windows API實現,或用托管代碼通過公共語言運行庫(cLR)的P/Invoke工具實現。目前,在Windows API的PNRP部分的.NET Framework中未包含托管包裝。但通過使用netsh命令行實用程序能訪問PRNP。命令向PNRP注冊—個新的PNRP名可以使用以下命令:
c:\emp>netsh
netsh>p2p pnrp peer
netsh p2p pnrp peer>add 0.baogxm
Ok.
0.baogxm即是P2P名。當此命令執行時,PNRP會生成--5\"-PNRP ID,將該PNRP ID與P2P名相關聯,并為該PNRP ID分配—個IPv6和IPv4地址。如果訪問另一臺已安裝PNRP并已啟動的計算機,則可以用以下netsh命令解析網格名0.baogxm:
netsh p2p pnrp peer>resolve 0.baogxm
Resolve started...
Found:Comment:gonzo//Comment字段代表注冊了0.baogxm的計算機名稱,該字段從netsh自動填充,并且不能用作解析進程的一部分
Addresses:[0000:0000:0000:0000:0000:0000:0000:0001]:8350 udp
210.41.35.1 99:8350 tcp
3 PeerChannel
WCF為許多不同類型的分布式應用程序提供了一個通用的編程模型。使用這個通用編程模型可以構建P2P應用程序。實際上,PeerChannel WCF模塊專用于構建P2P應用程序。
PeerChannel網格專為消息擴散而設計。PeerChannel網格的結構由每個節點所連接的鄰居數量所控制,PeerChannel網格會主動維護網格的結構。更具體點說,網格中的節點會將連接的鄰居數保持在2~7個之間,以使本地節點的資源需求與保持網格穩健性之間取得平衡。假設某節點在進入網格時帶有3個鄰居,隨后其中2個鄰居離開了網格,則該節點將開始一個維護周期以獲取新的鄰居。當一個PeerChannel節點連有3個鄰居時,則認為它處于理想的連接狀態,但一個節點可以接受多達7個鄰居,以便低于鄰居數最低閾值的節點能迅速獲得新的鄰居。應注意的是,應用程序不能更改這些閾值或對網格的維護實施任何控制,這些細節問題完全由PeerChannel基礎結構逐個節點地處理。
PeerChannel提供了PNRP解析程序和自定義解析程序,用于預期節點發現網格中已有節點的地址。這兩種方法都將網格名傳遞給解析程序并接收網格中其他節點的IP地址列表。一旦解析進程生成地址列表,預期PeerChannel節點就并發連接到每個地址。當PeerChannel網格中已有的節點收到其中一個連接請求時,它可以接受或拒絕該連接。如果接受該連接,則節點會向新連接的節點發送一條包含網格中其他節點地址列表的歡迎消息。如果拒絕該連接,則節點會向預期節點發送一條包含拒絕理由以及網格中其他節點地址列表的拒絕消息。
PeerChannel向預期節點返回地址列表的方式,不限于網格名解析(通過PNRP解析程序或自定義解析程序執行)。與將網格名解析作為預期節點獲取地址的惟一方法相比,這可使節點更快速地進入理想的連接狀態,也可使網格中的節點可對節點擁有的鄰居數(這一因素會進而影響網格的穩健性)進行控制。
PeerChannel網格內節點問傳送消息的重復率和網絡帶寬消耗較低。網格中的節點在網格內發送消息,實際上是在向其鄰居發送消息。收到消息后,每個鄰居都會檢驗該消息,然后將其轉發給自己的鄰居。節點從某鄰居收到消息,不會將此消息轉發回該鄰居。此外,如果節點多次從某鄰居收到先前已收到并處理過的消息,則與該鄰居的連接會在下一個維護周期中終止。這些功能是通過節點上的本地高速緩存來實現的。PeerChannel網格中的每個節點都會對WS-Addressing消息ID的值和傳送消息的鄰居的標識符進行緩存處理,在決定向哪些鄰居傳送該消息時會檢查這個高速緩存。
PeerChannel節點還可以將消息發送給網格中節點的子集。這通過向消息分配一個跳躍計數實現。跳躍計數是模糊界定接收消息的節點數的一種方法。例如,如果一個PeerChannel節點(節點A)有3個鄰居且在跳躍計數為1的情況下向網格發送一個消息,則該消息將被傳送到3個節點。同樣,如果節點A的每個鄰居也都有3個鄰居且節點A在跳躍計數為2的情況下向網格發送一個消息,則該消息將被傳送到9個節點。但如果節點A的任一鄰居有共用的鄰居,則此數字將相應減少。
從物理上說,跳躍計數在消息中被表示為標頭塊中的一個整數。當某節點收到帶有跳躍計數的消息時,它會檢查跳躍計數的值。如果該值大于零,節點會單調遞減此跳躍計數,然后將帶有遞減后的跳躍計數值的消息轉發給相應鄰居。如果節點所接收消息中包含的跳躍計數為0,則不轉發該消息。需要注意的是,跳躍計數標頭塊被排除在消息簽名之外,因此更改這個值不會影響到應用于消息的數字簽名的完整性,而且會避免產生與重復生成數字簽名并將其序列化到消息相應部分中的相關開銷。
4 People Near Me
PNM是集成在Windows Vista之中的一種網格技術,它允許鄰近的設備組和人員組相互發現、連接、邀請并進行協作。PNM是一項完全自選的網格技術,默認情況下處于關閉狀態。PNM體系結構包含了一個稱為p2phost.exe的P2P應用程序。此程序運行時,將通過連接到其他計算機上p2phost.exe的實例來創建網格。PNM用于解析本地節點并與這些本地節點的子集進行通信。PNM API作為Windows API的一部分,主要用于配置p2phost.exe。
5 PeerChannel實例
利用PeerChannel構建P2P應用程序的步驟如下:
(1)定義基本的Windows窗體樣板代碼。
(2)向窗體添加控件。
(3)定義必需的WCF服務合同。
(4)編寫連接到網格和從網格接收消息的WCF代碼。
(5)編寫向網格中其他節點發送消息的代碼。
對于任何WCF應用程序,開發過程的第一步是定義服務合同。PeerChannel要使用的服務合同類似于其他WCF合同,只不過PeerChannel中所有的OperationContractAttribute都將IsOneWay實例屬性設置為true。此屬性規定消息的接收方是否應發送回復。如果想要接收方發送回復,可以將服務合同定義為雙向合同,但每個OperationContractAttribute仍必須將IsOneWay實例屬性設置為true。定義合同代碼如下:
[ServiceContract]
interface IPictureViewer{
[OpemtionContract(IsOneWay=true)]//
void SharePicture(Stream stream)://SharePicture接口方法用
OperationContractAttdbute屬性加以說明,并且IsOneWay實例屬性被設置為true。此操作將被用于向網格中其他節點傳送圖片的字節
}
在定義了服務合同后,需要添加WCF代碼,該代碼會將我們的應用程序連接到PeerChannel網格并且被動等待來自網格的消息。首先,在窗體中實現新定義的服務合同;然后,定義類型ServiceHost的字段。所接收的消息將被發送到frmPictureViewer類型的單個實例。要顯示此功能,我們必須將正確的ServiceBehavior分配給frmPictureViewer類型。
接下來,必須對ServiceHost進行實例化,添加端點并開始偵聽外來的消息。由于構建的是Windows窗體應用程序,因此實現此操作的邏輯位置就是窗體的構造函數。到此,已經完成了連接到網格并偵聽消息所需的所有步驟。與標準的WCF代碼相比,只在URI的方案(net.p2p)、所使用的綁定(NetPeerTcpBinding)以及所增添的基于密碼的安全性方面有所不同。
只要調用了ServiceHost.Open,我們的應用程序就會通過PNRP來解析網格名(pictureView)。此時,可以通過運行netsh命令以列出注冊的對等名稱來驗證我們的PeerChannel應用程序是否正在使用PNRP。如果PNRP可以將網格名解析為一個或多個IP地址,則我們的應用程序將嘗試連接到這些節點。如果不是這樣,則該節點將成為網格中的第一個節點。如前所述,現有節點將通過發送歡迎消息或拒絕消息來接受或拒絕連接。這種情況有可能在對ServiceHost.Open的調用返回后發生。
加載共享圖片的代碼是Windows窗體基本代碼:首先,對OpenFileDialog進行實例化,獲得一個Stream,將該Stream轉換為Image,然后通過PictureBox.Image屬性引用Image。實際上,要將圖像加載到PictureBox中,只需調用Sharepicmm方法,將從OperlFileDialog.OpenFile返回的Stream作為參數傳遞。
要將包含圖片的消息發送到網格中的其他節點,需要在類型ChannelFactory和IPictureViewer的窗體中定義一些字段,然后在窗體的構造函數中將這些變量實例化。
請注意,所使用的網格密碼和證書(用于創建消息的數字簽名)必須與設置ServiceHost時所用的相同。此外,其代碼也要與非PeerChannel WCF應用程序中的代碼相同。
構建了發送基礎結構后,就可以使用它向網格中的其他節點發送消息。為此只需為共享按鈕編寫一個如下所示的事件處理程序:
private void btnShare_Click(object sender,EventArgs e)
{using(MemoryStream stream=new Memo~Stream())
{Image image=pbView.Image;
image.Save(stream,ImageFormat.Jpeg);
//將圖像存儲到stream中
stream.Position=O;//復位位置
channel.SharePicture(stream);//向網格發送消息
}
}
6 結束語
隨著Windows Vista和.NET Framework 3.0的發布,P2P應用程序的開發門檻將明顯降低。我們相信,技術的進步(如PNRP、IPv6)加上更具生產力的新型平臺的問世(如PeerChannel和PNM)將在P2P應用程序開發領域開創一個新時代。最終,應用程序將更具協作性,并完成我們原來只能想像的一些功能。
注:本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文。