http://blog.oraycn.com/ESFramework_Demo_P2P.aspx
測試,完全OK! 我很喜歡這個。可以源碼是加密的!我希望實現 web 版本的p2p視頻觀看,aehyok提出 用 SignalR 。要學習的東西很多啊。
msdn 上面有p2p 的局域網實例代碼下載。
ESFramework Demo -- P2P通信Demo(附源碼)
現在我們將在ESFramework Demo -- 文件傳送Demo 的基礎上,使用ESPlus提供的第四個武器,為其增加P2P通信的功能。在閱讀本文之前,請務必先掌握ESFramework 開發手冊(04) -- 可靠的P2P 一文中介紹的P2P的基礎知識以及相關API的用法。
本Demo主要演示以下功能:
(1)創建基於TCP的P2P通道
(2)創建基於UDP的P2P通道(內部使用可靠的UDP)
(3)使用P2P通道發送消息和傳送文件
一.服務端
在P2P打洞的過程中,服務端會參與協助P2P通道的建立,整個過程是由ESFramework/ESPlus內部自動完成的,而這個過程對於框架使用者是透明的。P2P通道創建后,客戶端與客戶端之間的通信就與服務器沒有任何關系了。所以我們直接把上一個demo的服務端拿過來用,不需要做任何修改。
二.客戶端
客戶端主要使用IRapidPassiveEngine提供的P2PController來查詢和控制P2P通道的狀態。
嘗試創建P2P通道
正如ESFramework 開發手冊(04) -- 可靠的P2P 一文中介紹的,並不是所有的客戶端之間的P2P通道都可以創建成功,創建P2P通道是一個嘗試的過程,IP2PController的P2PConnectAsyn方法就是嘗試與目標用戶創建P2P通道。
時機很重要。在何時創建P2P通道了?一般而言,是在兩個客戶端需要高頻通信之前,調用P2PConnectAsyn進行嘗試創建。
在本Demo中,我們是在每次打開與目標用戶的聊天窗口的時候,來嘗試創建P2P通道的。如下所示:
void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button != System.Windows.Forms.MouseButtons.Left)
{
return;
}
ListViewHitTestInfo info = this.listView1.HitTest(e.Location);
if (info.Item != null)
{
//嘗試與目標用戶建立P2P通道
this.rapidPassiveEngine.P2PController.P2PConnectAsyn(info.Item.Text);
ChatForm form = this.chatFormManager.GetForm(info.Item.Text);
......
}
}
使用P2PConnectAsyn方法開始打洞時,若雙方位於同一局域網,一般會建立起基於TCP的P2P通道;若雙方位於不同的網絡,一般會建立起基於UDP的P2P的通道。如果與目標用戶之間已經存在可用的P2P通道,則P2PConnectAsyn將不再做任何動作,而直接返回。
為了獲得P2P通道創建成功或失敗以及后續P2P通道被關閉的通知,demo中我們在MainForm的Initialize方法中預定了P2PController的P2PChannelOpened和P2PChannelClosed事件。
//預定P2P Channel創建成功的事件
this.rapidPassiveEngine.P2PController.P2PChannelOpened += new CbGeneric<P2PChannelState>(P2PController_P2PChannelOpened);
//預定P2P Channel關閉時的事件
this.rapidPassiveEngine.P2PController.P2PChannelClosed += new CbGeneric<P2PChannelState>(P2PController_P2PChannelClosed);
當P2P通道創建成功或被關閉時,本demo通過修改對應聊天窗口的Title文字來顯示這種狀態。比如,當P2P通道創建成功時,聊天窗口的Title顯示如下:
通常,如果兩個客戶端位於同一個LAN,或者有一個客戶端直接位於Internet上,則它們之間的P2P通道是基於TCP的;否則,創建的P2P通道是基於UDP的。
ChatForm提供了ShowP2PChannelState方法來顯示與聊天對象之間的P2P通道狀態。
///<summary>
/// 顯示P2P連接的狀態
///</summary>
public void ShowP2PChannelState(P2PChannelState state)
{
this.Text = (state != null) ? string.Format("正在與{0}對話中【{1}直連:{2}】...", this.friendID, state.ProtocolType, state.DestIPE) : string.Format("正在與{0}對話中...", this.friendID);
}
請注意,當與目標用戶之間沒有P2P通道時,P2PController的GetP2PChannelState方法返回的是null。
觀察P2P通信
當P2P通道創建成功后,兩個用戶之間的后續通信將經過P2P通道傳送,在本Demo中,表示后續的聊天消息以及文件傳送都將通過P2P通道進行。
那么,如何判斷消息是通過服務器中轉的,還是經過P2P通道直接傳送的了?我們常用的有兩個簡單的方法。
(1)觀察服務器的MainServerForm界面。
如果消息是經過服務器中轉的,那么界面上顯示消息接收者用戶對應的“下載次數”、“上傳次數”、“最后一次下載時間”等都會跟着發生變化。就本例來說,每當你給對方發送一個聊天消息,如果是經過服務器中轉,那么界面上顯示的對方的下載次數會增加1,自己的上傳次數也增加1,自己的最后一次上傳時間也會變化。而如果消息是通過P2P通道傳送的,這些數據就不會受影響。
(2)查看資源監視器
如果是Win7的系統,任務管理器“性能”顯示中提供了“資源監視器”,可以監控網絡的活動。使用它,我們就可以看到應用程序在和哪些機器進行通信。如下圖所示:
上面是我們另一個P2P應用demo的截圖,圖中59.175.145.163是服務器的IP,而我們看到OMCS.ClientDemo.exe接收數據的主要流量來自於ZY-PC這台電腦,這表示兩個客戶端之間的數據是經過P2P通道傳送的,沒有通過服務器中轉。之所以圖中顯示的客戶端與服務器之間還有微小的流量,那是由類似定時心跳消息等產生的。
如果不是Win7系統,也可以通過安裝網絡監控軟件(如NetLimiter)來查看這些信息。
三.源碼下載
-----------------------------------------------------------------------------------------------------------------------------------------------
Q Q:168757008