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)来查看这些信息。

三.源码下载

 ESFramework.Demos.P2P 源码

  

阅读 更多ESFramework开发手册系列文章

----------------------------------------------------------------------------------------------------------------------------------------------- 

关于ESFramework的任何问题,欢迎联系我们:

电话:027-87638960

Q Q:372841921

目录
相关文章
|
11月前
|
Ubuntu IDE Java
Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo
在arm上做了Qt的应用程序,为了在局域网实现web页的访问方式来配置arm上Qt的程序,局域网轻量级http服务器是很好的实现方式之一,有机会做国产麒麟上Qt的http服务器,正好接触到了QtWebApp可以实现。   本篇实战解说QtWebApp的轻量级Demo。   本篇篇幅较长,为了保持基础的完整性将必要的东西都放在本篇。
|
网络架构
SoapUI SoapUI测试WebService协议接口简介
SoapUI SoapUI测试WebService协议接口简介
74 0
|
编解码 JSON 负载均衡
rpc的正确打开方式|读懂Go原生net/rpc包
我希望借助这篇文章,用尽可能少的语言,配合分析Go原生net/rpc包的部分核心代码,帮助你贯通RPC的知识,梳理RPC的运作流程,让你对RPC有一个比较全面的认识。
165 0
rpc的正确打开方式|读懂Go原生net/rpc包
|
存储 JavaScript 网络协议
WebSocket接口初体验
这两天在调试一个WebSocket的接口,折腾了一天的时间终于弄好了。现在对WebSocket的相关知识点做一个记录。主要从如下几个方面进行介绍。
253 0
WebSocket接口初体验
❤️一个聊天室案例带你了解Node.js+ws模块是如何实现websocket通信的!
❤️一个聊天室案例带你了解Node.js+ws模块是如何实现websocket通信的!
181 0
❤️一个聊天室案例带你了解Node.js+ws模块是如何实现websocket通信的!
|
负载均衡 程序员 Go
Go RPC入门指南:RPC的使用边界在哪里?如何实现跨语言调用?
就是因为无法在同一个进程内,或者无法在同一个服务器上通过本地调用的方式实现我们的需求。 HTTP能满足需求但是不够高效,所以我们需要使用RPC。
145 0
Go RPC入门指南:RPC的使用边界在哪里?如何实现跨语言调用?
|
Java 程序员 网络安全
java版gRPC实战之六:客户端动态获取服务端地址
当服务端地址发生改变时,客户端不改配置不重启,就能感知到服务端的变化吗?
636 0
java版gRPC实战之六:客户端动态获取服务端地址
|
机器学习/深度学习 缓存 Cloud Native
Dubbo-go 源码笔记(二)客户端调用过程
有了上一篇文章《Dubbo-go 源码笔记(一)Server 端开启服务过程》的铺垫,可以类比客户端启动于服务端的启动过程。其中最大的区别是服务端通过 zk 注册服务,发布自己的ivkURL并订阅事件开启监听;而客户应该是通过zk注册组件,拿到需要调用的serviceURL,更新invoker并重写用户的RPCService,从而实现对远程过程调用细节的封装。
24904 0
Dubbo-go 源码笔记(二)客户端调用过程
|
网络协议 监控 API
ESFramework Demo -- P2P通信Demo(附源码)
现在我们将在ESFramework Demo -- 文件传送Demo 的基础上,使用ESPlus提供的第四个武器,为其增加P2P通信的功能。在阅读本文之前,请务必先掌握ESFramework 开发手册(04) -- 可靠的P2P 一文中介绍的P2P的基础知识以及相关API的用法。
1117 0