1. 程式人生 > >P2P對等網路技術原理整合

P2P對等網路技術原理整合

P2P(Peer to Peer)對等網路

P2P技術屬於覆蓋層網路(Overlay Network)的範疇,是相對於客戶機/伺服器(C/S)模式來說的一種網路資訊交換方式。在C/S模式中,資料的分發採用專門的伺服器,多個客戶端都從此伺服器獲取資料。

優點是:資料的一致性容易控制,系統也容易管理。

缺點是:因為伺服器的個數只有一個(即便有多個也非常有限),系統容易出現單一失效點;單一伺服器面對眾多的客戶端,由於CPU能力、記憶體大小、網路頻寬的限制,可同時服務的客戶端非常有限,可擴充套件性差。

P2P技術正是為了解決這些問題而提出來的一種對等網路結構。在P2P網路中,每個節點既可以從其他節點得到服務,也可以向其他節點提供服務。這樣,龐大的終端資源被利用起來,一舉解決了C/S模式中的兩個弊端。


P2P應用軟體主要包括檔案分發軟體、語音服務軟體、流媒體軟體。目前P2P應用種類多、形式多樣,沒有統一的網路協議標準,其體系結構和組織形式也在不斷髮展。

對等網路的基本結構


(1)集中式對等網路(Napster、QQ)

集中式對等網路基於中央目錄伺服器,為網路中各節目提供目錄查詢服務,傳輸內容無需再經過中央伺服器。這種網路,結構比較簡單,中央伺服器的負擔大大降低。但由於仍存在中央節點,容易形成傳輸瓶頸,擴充套件性也比較差,不適合大型網路。但由於目錄集中管理,對於小型網路的管理和控制上倒是一種可選擇方案。

(2)無結構分散式網路Gnutella

無結構分散式網路與集中式的最顯著區別在於,它沒有中央伺服器,所有結點通過與相鄰節點間的通訊,接入整個網路。在無結構的網路中,節點採用一種查詢包的機制來搜尋需要的資源。具體的方式為,某節點將包含查詢內容的查詢包傳送到與之相鄰的節點,該查詢包以擴散的方式在網路中蔓延,由於這樣的方式如果不加節制,會造成訊息氾濫,因此一般會設定一個適當的生存時間(TTL),在查詢的過程中遞減,當TTL值為0時,將不再繼續傳送。

   這種無結構的方式,組織方式比較鬆散,節點的加入與離開比較自由,當查詢熱門內容時,很容易就能找到,但如果需求的內容比較冷門,較小的TTL不容易找到,而較大的TTL值又容易引起較大的查詢流量,尤其當網路範圍擴充套件到一定規模時,即使限制的TTL值較小,仍然會引起流量的劇增。但當網路中存在一些擁有豐富資源的所謂的類伺服器節點時,可顯著提高查詢的效率。

(3)結構化分散式網路第三代P2P Pastry、Tapestry、Chord、CAN)

    結構化分散式網路,是近幾年基於分散式雜湊表(Distributed Hash Table)技術的研究成果。它的基本思想是將網路中所有的資源整理成一張巨大的表,表內包含資源的關鍵字和所存放結點的地址,然後將這張表分割後分別儲存到網路中的每一結點中去。當用戶在網路中搜索相應的資源時,它將能發現儲存與關鍵詞對應的雜湊表內容所存放的結點,在該結點中儲存了包含所需資源的結點地址,然後發起搜尋的結點根據這些地址資訊,與對應結點連線並傳輸資源。這是一種技術上比較先進的對等網路,它具有高度結構化,高可擴充套件性,結點的加入與離開比較自由。這種方式適合比較大型的網路。

對等網路經典結構   (1)DHT結構

    分散式雜湊表(DHT)[1]是一種功能強大的工具,它的提出引起了學術界一股研究DHT的熱潮。雖然DHT具有各種各樣的實現方式,但是具有共同的特徵,即都是一個環行拓撲結構,在這個結構裡每個節點具有一個唯一的節點標識(ID),節點ID是一個128位的雜湊值。每個節點都在路由表裡儲存了其他前驅、後繼節點的ID。如圖1(a)所示。通過這些路由資訊,可以方便地找到其他節點。這種結構多用於檔案共享和作為底層結構用於流媒體傳輸[2]。

    (2)樹形結構     P2P網路樹形結構如圖1(b)所示。在這種結構中,所有的節點都被組織在一棵樹中,樹根只有子節點,樹葉只有父節點,其他節點既有子節點也有父節點。資訊的流向沿著樹枝流動。最初的樹形結構多用於P2P流媒體直播[3-4]。     (3)網狀結構

    網狀結構如圖1(c)所示,又叫無結構。顧名思義,這種結構中,所有的節點無規則地連在一起,沒有穩定的關係,沒有父子關係。網狀結構[5]為P2P提供了最大的容忍性、動態適應性,在流媒體直播和點播應用中取得了極大的成功。當網路變得很大時,常常會引入超級節點的概念,超級節點可以和任何一種以上結構結合起來組成新的結構,如KaZaA[6]。


P2P技術應用

(1)分散式科學計算
P2P技術可以使得眾多終端的CPU資源聯合起來,服務於一個共同的計算。這種計算一般是計算量巨大、資料極多、耗時很長的科學計算。在每次計算過程中,任務(包括邏輯與資料等)被劃分成多個片,被分配到參與科學計算的P2P節點機器上。在不影響原有計算機使用的前提下,人們利用分散的CPU資源完成計算任務,並將結果返回給一個或多個伺服器,將眾多結果進行整合,以得到最終結果。
(2)檔案共享
BitTorrent是一種無結構的網路協議。除了BitTorrent之外,還有不少著名的無結構化的P2P檔案共享協議,典型的有Gnutella[8]和KaZaA[6]。
(3)流媒體直播
(4)流媒體點播
(5)IP層語音通訊
Skype採取類似KaZaA的拓撲結構,在網路中選取一些超級節點。在通訊雙方直連效果不好時,一些合適的超級節點則擔當起其中轉節點的角色,為通訊雙方建立中轉連線,並轉發相應的語音通訊包。

典型P2P應用的機制分析
分析典型的P2P應用機制可以深入瞭解P2P的原理。本節將對檔案分發、流媒體應用、語音服務3個領域中具有代表性的軟體機制進行詳細的分析。對於這些軟體的分析有助於理解P2P技術的原理和把握P2P技術未來發展的趨勢。

BitTorrent
BitTorrent軟體使用者首先從Web伺服器上獲得下載檔案的種子檔案,種子檔案中包含下載檔名及資料部分的雜湊值,還包含一個或者多個的索引(Tracker)伺服器地址。它的工作過程如下:客戶端向索引伺服器發一個超文字傳輸協議(HTTP)的GET請求,並把它自己的私有資訊和下載檔案的雜湊值放在GET的引數中;索引伺服器根據請求的雜湊值查詢內部的資料字典,隨機地返回正在下載該檔案的一組節點,客戶端連線這些節點,下載需要的檔案片段。因此可以將索引伺服器的檔案下載過程簡單地分成兩個部分:與索引伺服器通訊的HTTP,與其他客戶端通訊並傳輸資料的協議,我們稱為BitTorrent對等協議。BitTorrent軟體的工作原理如圖4所示。BitTorrent協議也處在不斷變化中,可以通過資料報協議(UDP)和DHT的方法獲得可用的傳輸節點資訊,而不是僅僅通過原有的HTTP,這種方法使得BitTorrent應用更加靈活,提高BitTorrent使用者的下載體驗。

eMule
eMule軟體基於eDonkey協議改進後的協議,同時相容eDonkey協議。每個eMule客戶端都預先設定好了一個伺服器列表和一個本地共享檔案列表,客戶端通過TCP連線到eMule伺服器進行登入,得到想要的檔案的資訊以及可用的客戶端的資訊。一個客戶端可以從多個其他的EMule客戶端下載同一個檔案,並從不同的客戶端取得不同的資料片段。eMule同時擴充套件了eDonkey的能力,允許客戶端之間互相交換關於伺服器、其他客戶端和檔案的資訊。eMule伺服器不儲存任何檔案,它只是檔案位置資訊的中心索引。eMule客戶端一啟動就會自動使用傳輸控制協議(TCP)連線到eMule伺服器上。伺服器給客戶端提供一個客戶端標識(ID),它僅在客戶端伺服器連線的生命週期內有效。連線建立後,客戶端把其共享的檔案列表傳送給伺服器。伺服器將這個列表儲存在內部資料庫內。eMule客戶端也會發送請求下載列表。連線建立以後,eMule伺服器給客戶端返回一個列表,包括哪些客戶端可以提供請求檔案的下載。然後,客戶端再和它們主動建立連線下載檔案。圖5所示為eMule的工作原理。


eMule基本原理與BitTorrent類似,客戶端通過索引伺服器獲得檔案下載資訊。eMule同時允許客戶端之間傳遞伺服器資訊,BitTorrent只能通過索引伺服器或者DHT獲得。eMule共享的是整個檔案目錄,而BitTorrent只共享下載任務,這使得BitTorrent更適合分發熱門檔案,eMule傾向於一般熱門檔案的下載。

迅雷
迅雷是一款新型的基於多資源多執行緒技術的下載軟體,迅雷擁有比目前使用者常用的下載軟體快7~10倍的下載速度。迅雷的技術主要分成兩個部分,一部分是對現有Internet下載資源的搜尋和整合,將現有Internet上的下載資源進行校驗,將相同校驗值的統一資源定位(URL)資訊進行聚合。當用戶點選某個下載連線時,迅雷伺服器按照一定的策略返回該URL資訊所在聚合的子集,並將該使用者的資訊返回給迅雷伺服器。另一部分是迅雷客戶端通過多資源多執行緒下載所需要的檔案,提高下載速率。迅雷高速穩定下載的根本原因在於同時整合多個穩定伺服器的資源實現多資源多執行緒的資料傳輸。多資源多執行緒技術使得迅雷在不降低使用者體驗的前提下,對伺服器資源進行均衡,有效降低了伺服器負載。

每個使用者在網上下載的檔案都會在迅雷的伺服器中進行資料記錄,如有其他使用者再下載同樣的檔案,迅雷的伺服器會在它的資料庫中搜索曾經下載過這些檔案的使用者,伺服器再連線這些使用者,通過使用者已下載檔案中的記錄進行判斷,如使用者下載檔案中仍存在此檔案(檔案如改名或改變儲存位置則無效),使用者將在不知不覺中扮演下載中間服務角色,上傳檔案。

PPLive
PPLive軟體的工作機制和BitTorrent十分類似,PPLive將視訊檔案分成大小相等的片段,第三方提供播放的視訊源,使用者啟礬PPLive以後,從PPLive伺服器獲得頻道的列表,使用者點選感興趣的頻道,然後從其他節點獲得資料檔案,使用流媒體實時傳輸協議(RTP)和實時傳輸控制協議(RTCP)進行資料的傳輸和控制。將資料下載到本地主機後,開放本地埠作為視訊伺服器,PPLive的客戶端播放器連線此埠,任何同一個區域網內的使用者都可以通過連線這個地址收看到點播的節目。圖6所示為PPLive的工作原理示意圖。

Skype
Skype是網路語音溝通工具。它可以提供免費高清晰的語音對話,也可以用來撥打國內國際長途,還具備即時通訊所需的其他功能,比如檔案傳輸、文字聊天等。Skype是在KaZaA的基礎上開發的,就像KaZaA一樣,Skype本身也是基於覆蓋層的P2P網路,在它裡面有兩種型別的節點:普通節點和超級節點。普通節點是能傳輸語音和訊息的一個功能實體;超級節點則類似於普通節點的網路閘道器,所有的普通節點必須與超級節點連線,並向Skype的登陸伺服器註冊它自己來加入Skype網路。Skype的登陸伺服器上存有使用者名稱和密碼,並且授權特定的使用者加入Skype網路,圖7所示為Skype的體系結構[18]


Skype的另一個突出特點就是能夠穿越地址轉換裝置和防火牆。Skype能夠在最小傳輸頻寬32 kb/s的網路上提供高質量的語音。Skype是使用P2P語音服務的代表。由於其具有超清晰語音質量、極強的穿透防火牆能力、免費多方通話以及高保密性等優點,成為網際網路上使用最多的P2P應用之一。

P2P實現的原理 首先先介紹一些基本概念: NAT(Network Address Translators),網路地址轉換:網路地址轉換是在IP地址日益缺乏的情況下產生的,它的主要目的就是為了能夠地址重用。NAT從歷史發展上分為兩大類,基本的NAT和NAPT(Network Address/Port Translator)。    最先提出的是基本的NAT(peakflys注:剛開始其實只是路由器上的一個功能模組),它的產生基於如下事實:一個私有網路(域)中的節點中只有很少的節點需要與外網連線(這是在上世紀90年代中期提出的)。那麼這個子網中其實只有少數的節點需要全球唯一的IP地址,其他的節點的IP地址應該是可以重用的。 因此,基本的NAT實現的功能很簡單,在子網內使用一個保留的IP子網段,這些IP對外是不可見的。子網內只有少數一些IP地址可以對應到真正全球唯一的IP地址。如果這些節點需要訪問外部網路,那麼基本NAT就負責將這個節點的子網內IP轉化為一個全球唯一的IP然後傳送出去。(基本的NAT會改變IP包中的原IP地址,但是不會改變IP包中的埠) 關於基本的NAT可以參看RFC 1631 另外一種NAT叫做NAPT,從名稱上我們也可以看得出,NAPT不但會改變經過這個NAT裝置的IP資料報的IP地址,還會改變IP資料報的TCP/UDP埠。基本NAT的裝置可能我們見的不多(基本已經淘汰了),NAPT才是我們真正需要關注的。看下圖:

有一個私有網路10.*.*.*,Client A是其中的一臺計算機,這個網路的閘道器(一個NAT裝置)的外網IP是155.99.25.11(應該還有一個內網的IP地址,比如10.0.0.10)。如果Client A中的某個程序(這個程序建立了一個UDP Socket,這個Socket繫結1234埠)想訪問外網主機18.181.0.31的1235埠,那麼當資料包通過NAT時會發生什麼事情呢?
首先NAT會改變這個資料包的原IP地址,改為155.99.25.11。接著NAT會為這個傳輸建立一個Session(Session是一個抽象的概念,如果是TCP,也許Session是由一個SYN包開始,以一個FIN包結束。而UDP呢,以這個IP的這個埠的第一個UDP開始,結束呢,呵呵,也許是幾分鐘,也許是幾小時,這要看具體的實現了)並且給這個Session分配一個埠,比如62000,然後改變這個資料包的源埠為62000。所以本來是 (10.0.0.1:1234->18.181.0.31:1235)的資料包到了網際網路上變為了(155.99.25.11:62000->18.181.0.31:1235)。 一旦NAT建立了一個Session後,NAT會記住62000埠對應的是10.0.0.1的1234埠,以後從18.181.0.31傳送到62000埠的資料會被NAT自動的轉發到10.0.0.1上。(注意:這裡是說18.181.0.31傳送到62000埠的資料會被轉發,其他的IP傳送到這個埠的資料將被NAT拋棄)這樣Client A就與Server S1建立以了一個連線。 上面的是一些基礎知識,下面的才是關鍵的部分了。 看看下面的情況:

接上面的例子,如果Client A的原來那個Socket(綁定了1234埠的那個UDP Socket)又接著向另外一個Server S2傳送了一個UDP包,那麼這個UDP包在通過NAT時會怎麼樣呢?
這時可能會有兩種情況發生,一種是NAT再次建立一個Session,並且再次為這個Session分配一個埠號(比如:62001)。另外一種是NAT再次建立一個Session,但是不會新分配一個埠號,而是用原來分配的埠號62000。前一種NAT叫做Symmetric NAT,後一種叫做Cone NAT。如果你的NAT剛好是第一種,那麼很可能會有很多P2P軟體失靈。(可以慶幸的是,現在絕大多數的NAT屬於後者,即Cone NAT) peakflys注:Cone NAT具體又分為3種: (1)全圓錐( Full Cone) : NAT把所有來自相同內部IP地址和埠的請求對映到相同的外部IP地址和埠。任何一個外部主機均可通過該對映傳送IP包到該內部主機。 (2)限制性圓錐(Restricted Cone) : NAT把所有來自相同內部IP地址和埠的請求對映到相同的外部IP地址和埠。但是,只有當內部主機先給IP地址為X的外部主機發送IP包,該外部主機才能向該內部主機發送IP包。 (3)埠限制性圓錐( Port Restricted Cone) :埠限制性圓錐與限制性圓錐類似,只是多了埠號的限制,即只有內部主機先向IP地址為X,埠號為P的外部主機發送1個IP包,該外部主機才能夠把源埠號為P的IP包傳送給該內部主機。 好了,我們看到,通過NAT,子網內的計算機向外連結是很容易的(NAT相當於透明的,子網內的和外網的計算機不用知道NAT的情況)。 但是如果外部的計算機想訪問子網內的計算機就比較困難了(而這正是P2P所需要的)。 那麼我們如果想從外部發送一個數據報給內網的計算機有什麼辦法呢?首先,我們必須在內網的NAT上打上一個“洞”(也就是前面我們說的在NAT上建立一個Session),這個洞不能由外部來打,只能由內網內的主機來打。而且這個洞是有方向的,比如從內部某臺主機(比如:192.168.0.10)向外部的某個IP(比如:219.237.60.1)傳送一個UDP包,那麼就在這個內網的NAT裝置上打了一個方向為219.237.60.1的“洞”,(這就是稱為UDP Hole Punching的技術)以後219.237.60.1就可以通過這個洞與內網的192.168.0.10聯絡了。(但是其他的IP不能利用這個洞)。 P2P的常用實現 一、普通的直連式P2P實現 通過上面的理論,實現兩個內網的主機通訊就差最後一步了:那就是雞生蛋還是蛋生雞的問題了,兩邊都無法主動發出連線請求,誰也不知道誰的公網地址,那我們如何來打這個洞呢?我們需要一箇中間人來聯絡這兩個內網主機。 現在我們來看看一個P2P軟體的流程,以下圖為例: 首先,Client A登入伺服器,NAT A為這次的Session分配了一個埠60000,那麼Server S收到的Client A的地址是202.187.45.3:60000,這就是Client A的外網地址了。同樣,Client B登入Server S,NAT B給此次Session分配的埠是40000,那麼Server S收到的B的地址是187.34.1.56:40000。 此時,Client A與Client B都可以與Server S通訊了。如果Client A此時想直接傳送資訊給Client B,那麼他可以從Server S那兒獲得B的公網地址187.34.1.56:40000,是不是Client A向這個地址傳送資訊Client B就能收到了呢?答案是不行,因為如果這樣傳送資訊,NAT B會將這個資訊丟棄(因為這樣的資訊是不請自來的,為了安全,大多數NAT都會執行丟棄動作)。現在我們需要的是在NAT B上打一個方向為202.187.45.3(即Client A的外網地址)的洞,那麼Client A傳送到187.34.1.56:40000的資訊,Client B就能收到了。這個打洞命令由誰來發呢?自然是Server S。 總結一下這個過程:如果Client A想向Client B傳送資訊,那麼Client A傳送命令給Server S,請求Server S命令Client B向Client A方向打洞。然後Client A就可以通過Client B的外網 地址與Client B通訊了。 注意:以上過程只適合於Cone NAT的情況,如果是Symmetric NAT,那麼當Client B向Client A打洞的埠已經重新分配了,Client B將無法知道這個埠(如果Symmetric NAT的埠是順序分配的,那麼我們或許可以猜測這個埠號,可是由於可能導致失敗的因素太多,這種情況下一般放棄P2P  ---peakflys)。 二、STUN方式的P2P實現 STUN是RFC3489規定的一種NAT穿透方式,它採用輔助的方法探測NAT的IP和埠。毫無疑問的,它對穿越早期的NAT起了巨大的作用,並且還將繼續在NAT穿透中佔有一席之地。 STUN的探測過程需要有一個公網IP的STUN server,在NAT後面的UAC必須和此server配合,互相之間傳送若干個UDP資料包。UDP包中包含有UAC需要了解的資訊,比如NAT外網IP,PORT等等。UAC通過是否得到這個UDP包和包中的資料判斷自己的NAT型別。 假設有如下UAC(B),NAT(A),SERVER(C),UAC的IP為IPB,NAT的IP為 IPA ,SERVER的 IP為IPC1 、IPC2。請注意,伺服器C有兩個IP,後面你會理解為什麼需要兩個IP。 (1)NAT的探測過程 STEP1:B向C的IPC1的port1埠傳送一個UDP包。C收到這個包後,會把它收到包的源IP和port寫到UDP包中,然後把此包通過IP1C和port1發還給B。這個IP和port也就是NAT的外網IP和port,也就是說你在STEP1中就得到了NAT的外網IP。 熟悉NAT工作原理的應該都知道,C返回給B的這個UDP包B一定收到。如果在你的應用中,向一個STUN伺服器傳送資料包後,你沒有收到STUN的任何迴應包,那只有兩種可能:1、STUN伺服器不存在,或者你弄錯了port。2、你的NAT裝置拒絕一切UDP包從外部向內部通過,如果排除防火牆限制規則,那麼這樣的NAT裝置如果存在,那肯定是壞了„„ 當B收到此UDP後,把此UDP中的IP和自己的IP做比較,如果是一樣的,就說明自己是在公網,下步NAT將去探測防火牆型別,就不多說了(下面有圖)。如果不一樣,說明有NAT的存在,系統進行STEP2的操作。 STEP2:B向C的IPC1傳送一個UDP包,請求C通過另外一個IPC2和PORT(不同與SETP1的IP1)向B返回一個UDP資料包(現在知道為什麼C要有兩個IP了吧,為了檢測cone NAT的型別)。 我們來分析一下,如果B收到了這個資料包,那說明什麼?說明NAT來著不拒,不對資料包進行任何過濾,這也就是STUN標準中的full cone NAT。遺憾的是,full cone nat太少了,這也意味著你能收到這個資料包的可能性不大。如果沒收到,那麼系統進行STEP3的操作。 STEP3:B向C的IPC2的port2傳送一個數據包,C收到資料包後,把它收到包的源IP和port寫到UDP包中,然後通過自己的IPC2和port2把此包發還給B。 和step1一樣,B肯定能收到這個迴應UDP包。此包中的port是我們最關心的資料,下面我們來分析: 如果這個port和step1中的port一樣,那麼可以肯定這個NAT是個CONE NAT,否則是對稱NAT。道理很簡單:根據對稱NAT的規則,當目的地址的IP和port有任何一個改變,那麼NAT都會重新分配一個port使用,而在step3中,和step1對應,我們改變了IP和port。因此,如果是對稱NAT,那這兩個port肯定是不同的。 如果在你的應用中,到此步的時候PORT是不同的,那就只能放棄P2P了,原因同上面實現中的一樣。如果不同,那麼只剩下了restrict cone 和port restrict cone。系統用step4探測是是那一種。 STEP4:B向C的IP2的一個埠PD傳送一個數據請求包,要求C用IP2和不同於PD的port返回一個數據包給B。 我們來分析結果:如果B收到了,那也就意味著只要IP相同,即使port不同,NAT也允許UDP包通過。顯然這是restrict cone NAT。如果沒收到,沒別的好說,port restrict NAT. 協議實現的演算法執行圖如下:
一旦路經到達紅色節點時,UDP的溝通是沒有可能性的(peakflys注:準備來說除了包被防火牆blocked之外,其他情況也是有可能建立P2P的,只是代價太大,一般放棄)。一旦通過黃色或是綠色的節點,就有連線的可能。 最終通過STUN伺服器得到自己的NAT型別和公網IP、Port,以後建立P2P時就非常容易了。

參考文章: