(本文适用于ESFramework V0.3+)
在ESFramework介绍之(7)-- 服务器代理IServerAgent 一文中,我们详细的介绍了IServerAgent,我们已经知道,客户端与服务器之间的所有通信都可经过IServerAgent,包括要转发的P2P消息。IServerAgent的主要目的是:
(1)屏蔽客户端与服务端之间的通信协议(Tcp/Udp),ITcpServerAgent、IUdpServerAgent
(2)可将异步的消息请求/回复转化为同步的方法调用。
客户端与服务端的所有交互都可以通过IServerAgent进行,但是如果客户A与客户B之间直接进行P2P通信了?那么A和B之间的P2PMessage就不需要经过服务器转发,即不需要提交给IServerAgent,而是交给IP2PChannel发送;如果客户A和客户B之间不能直接通信,那么A和B之间的P2PMessage就需要经过服务器转发。
为了对上层应用屏蔽P2PMessage是通过服务器转发器的还是通过IP2PChannel直接发送的,ESFramework引入了IMessageTransceiver,它的智能在于,如果P2PMessage可以通过IP2PChannel直接发送,则将其交给IP2PChannel,否则将其提交给IServerAgent由服务器转发。这样应用只需要直接使用IMessageTransceiver提交(发送)消息就可以了,而不用关心下层的消息路由途径。
IMessageTransceiver接口定义如下:
{
/// <summary>
/// 如果超时仍然没有回复,则抛出超时异常
/// 如果dataPriority != DataPriority.CanBeDiscarded ,则checkRespond只能为false
/// </summary>
NetMessage CommitRequest(NetMessage requestMsg ,DataPriority dataPriority , bool checkRespond);
IP2PChannelManager P2PChannelManager{set ;}
IServerAgent ServerAgent{set ;}
IPassiveHelper PassiveHelper{set ;}
}
IMessageTransceiver及其相关组件关系图如下:
我们看到,整个应用所有的消息收发都可以通过IMessageTransceiver进行,而不用在去操作IServerAgent了(当然,我们可以完全在IServerAgent的基础上构建应用,而不关心IMessageTransceiver的存在)。当有消息发送/提交(无论是基本消息、功能请求消息、还是P2P消息)时,直接提交给IMessageTransceiver即可。IMessageTransceiver对要发送的消息采取如下流程:
(1)如果是非P2P消息,则直接提交给IServerAgent。
(2)如果是P2P消息,然后向p2PChannelManager查询针对目标客户的P2PChannel是否存在,如果存在,则直接通过P2PChannel发送;否则,就提交给IServerAgent进行转发。
以下是IMessageTransceiver实现这个流程的代码:
{
//通过IP2PChannel发送P2PMessage
if(this.passiveHelper.GetPassiveMessageType(requestMsg.Header.ServiceKey) == PassiveMessageType.P2PMessage)
{
IP2PChannel channel = this.p2PChannelManager.GetP2PChannel(requestMsg.Header.DestUserID) ;
if(channel != null)
{
channel.SendMessage(requestMsg) ;
if(checkRespond)
{
return this.responseManager.PickupResponse(requestMsg.Header.ServiceKey ,requestMsg.Header.CorrelationID) ;
}
return null ;
}
}
return this.serverAgent.CommitRequest(requestMsg ,dataPriority ,checkRespond) ;
}
IP2PChannelManager组件用于管理当前客户与每个其它客户之间的P2P通道,它需要根据服务端发回的其它用户的地址、状态等信息来构建、销毁对应的P2P通道(IP2PChannel)。
{
IP2PChannel GetP2PChannel(string destUserID) ;
}
IP2PChannel,如其名,它是客户与客户之间P2P通信的信道的抽象,很显然,目前最常用的P2P通道是基于UDP的NAT穿透的通道,这是IP2PChannelManager的实现之一。如果可能(比如不同的客户位于同一局域网内部),我们也可以在客户之间使用基于Tcp 的P2P通道。IP2PChannel接口定义如下:
{
void SendMessage(NetMessage msg) ;
}
现在,使用ESFramework,我们可以在三个层次上构建你的客户端应用:
(1)直接在NetworkStream或Socket上构建,这样可以完全抛开ESFramework,但是这也需要你自己手动的处理所有麻烦的东西。
(2)在ITcpServerAgent上构建,这样ESFramework会帮你做好所有消息的收发,请求与回复的匹配,消息的优先级分类、消息的自动发送等等。
(3)在IMessageTransceiver构建,到这里,你甚至不用关心你的P2P消息是通过P2PChannel直接发送的还是通过服务器进行中转的。底层的通信方式对于你的应用是透明的。
在后面介绍NAPT穿透时,我会给出基于NAPT的IP2PChannel实现和对应的IMessageTransceiver实现。感谢关注!
上一篇:ESFramework介绍之(34)―― ITcpServerAgent和IUdpServerAgent组件关系图
转到 :ESFramework 可复用的应用框架(序)