基于ESFramework的P2P实现 —— ESFramework扩展之EsfP2P
好久没有写关于ESFramework的文章了,曾很早就承诺过要写一篇介绍基于ESFramework实现NAPT P2P的文章,今天终于能抽出时间做这件事。
网络地址转换NAT(或者NAPT)的基本理论知识,网上有很多相关资料,不是很清楚的朋友可以先了解下什么是NAT、以及为什么要使用NAT。使用NAT的一个非常常见的场合就是P2P技术,要使两个隐藏在不同的局域网后面机器能够相互通信,并不是一件非常简单的事情,因为,这两台机器没有公网地址,相互之间是无法直接通过IPEndPoint访问的。NAT解决了这个问题,虽然并不是所有的操作系统都完整的支持NAT,幸运的是,主流的操作系统一般都是支持的。
通常,NAT都支持UDP,支持Tcp的NAT实现非常少见(也非常难以实现)。我们现有的P2P技术也几乎全是基于UDP的。
相互通信的两台机器,首先要通过服务器建立起P2P Session,这个过程必须有服务器的参与,否则Session无法建立起来。在P2P Session建立完成之后,两台机器之间就可以进行P2P通信了,而不必再经过服务器中转。
基于ESFramework的扩展EsfP2P就是C#版本的一个P2P实现,它用于协助P2P Session的建立。使用EsfP2P,我们写程序时不用再关心与如何搭建与P2P Session的一切事宜。
在P2P Session能被EsfP2P自动建立后,对应的IP2PChannel就可以使用了,你还记得IMessageTransceiver吗?IMessageTransceiver的智能在于,如果P2PMessage可以通过IP2PChannel直接发送,则将其交给IP2PChannel,否则将其提交给IServerAgent由服务器转发。这样应用只需要直接使用IMessageTransceiver提交(发送)消息就可以了,而不用关心下层的消息路由途径。
回顾一下图示:
ESFramework的扩展之一NaptP2P,就是用于自动搭建各个IP2PChannel,并使之可用。一旦Client1和Client2之间的IP2PChannel构建成功,它们之间的通信就可以直接进行。
说了这么久的EsfP2P,对其还没有感性的认识。下面我们来详细介绍它。
EsfP2P的主要目的是协助P2P Session的搭建(即各个IP2PChannel实例的构建),这需要客户端和服务端相互协作来完成这件事情。
关于NAT的“hole”(“打洞”)过程以建立P2P Session的理论,可参阅其它相关资料(如http://hwycheng.blogchina.com/)。这里列出EsfP2P采用的“hole”过程:
(1)服务器管理所有在线用户的Udp地址
(2)ClientA登录时从服务器获取所有在线好友的Udp地址列表
(3)ClientA初始化时,根据好友地址列表向所有在线好友发送P2PCheckMessage
(4)以后ClientA定时向NaptP2PChannelManager管理的各个通道发送DirectP2PCheck消息
(5)当某个Client收到P2PCheckMessage,则将对应的用户注册到NaptP2PChannelManager
(6)当某个Client上线时,服务器通知所有其它用户,用户接到通知后,立即向该Client发送P2PCheckMessage
(7)当某个Client下线/掉线时,服务器通知所有其它用户,用户接到通知后,从NaptP2PChannelManager中注销下线的用户
EsfP2P通过执行上述的要点,可以保证P2P Session的正确建立。在实现这些要点时,需要引入一系列类型的消息,这些消息类型可由P2PSessionMessageType的属性展现:
AskForFriendP2PAddresses消息用于客户端向服务器请求所有好友的P2P地址;P2PCheckMessage用于Check两个端点之间的P2P Session是否成功建立,一旦一个端点接收到了另一个端点发来的P2PCheckMessage,就说明两个端点之间的P2P Session已经建立成功了。P2PLogon和P2PLogout是客户端登陆或退出时发送给服务器的消息。SomeOneLogon和SomeOneLogout是当某个用户上线、下线时,服务器给其它用户的通知。
EsfP2P中分别提供了对服务端(EsfP2P.Server空间)和客户端(EsfP2P.Passive空间)的支持。在服务端,主要是P2PSessionDealer组件,UserP2PAddressManager组件。
P2PSessionDealer实现了IDataDealer接口,是一个简单的消息处理器,用于处理所有与P2PSession创建相关的消息,如AskForFriendP2PAddresses消息、P2PLogon和P2PLogout。
UserP2PAddressManager用于管理所有客户的P2P地址,并且当某用户上/下线时,要发送SomeOneLogon和SomeOneLogout消息通知这个用户的好友。其接口IUserP2PAddressManager类图如下:
IUserP2PAddressManager 既可用于服务端、也可用于客户端:
(1)在服务端主要被P2PSessionDealer填充,另外用户掉线事件也应触发UnRegister调用
(2)在客户端主要被P2PSessionPassiveDealer填充,另外用户离线事件也应触发UnRegister调用
下面看EsfP2P对客户端的支持。
客户端的核心接口是INaptOutter,它封装了所有与服务端或其它客户端进行有关NAPT Session的交互。
当客户端登录时调用INaptOutter.P2PLogon方法;退出时调用INaptOutter.P2PLogout方法;GetFriendP2PAddress用于获取所有在线好友的P2P地址。
客户端的另一个重要组件是P2PSessionChecker,它用于定时向所有在线好友发送P2PCheckMessage(通过调用INaptOutter.SendP2PCheckMessage方法),这样那些后上线的客户也可以通过这个P2PCheckMessage来判断P2P Session的建立。
还有一个客户端的消息处理器P2PSessionPassiveDealer,它实现了IDataDealer接口,也是一个简单的消息处理器,用于在客户端处理所有与P2P Session搭建相关的消息。
关于EsfP2P的主要组件就是这些,那么如何使用它来构建P2P应用了?(使用EsfP2P的前提是,使用了ESFramework)
(1)首先在一个公共dll中配置P2PSessionMessageType,它将被服务端和客户端使用。
(2)在服务端配置P2PSessionDealer组件,并将其装配到处理器工厂。
(3)在服务端配置UserP2PAddressManager组件,并通过UserP2PAddressManagerBridge桥接UserP2PAddressManager与IUserManager。
(4)在客户端配置NaptOutter组件。
(5)在客户端配置P2PSessionPassiveDealer组件,并将其装配到客户端的处理器工厂。
(6)在客户端配置NaptP2PChannelManager组件,并将其装配到IMessageTransceiver组件。
(7)在客户端配置P2PSessionChecker组件,并在登录时调用其Initialize方法。
EsfP2P.dll可以到ESFramework 可复用的应用框架(序) 下载部分下载试用。
感谢关注!
转到 :ESFramework 可复用的应用框架(序)