天天看點

ESFramework介紹之(35)―― IMessageTransceiver

    (本文适用于ESFramework V0.3+)

(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接口定義如下:

    public interface 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及其相關元件關系圖如下:

ESFramework介紹之(35)―― IMessageTransceiver

    我們看到,整個應用所有的消息收發都可以通過IMessageTransceiver進行,而不用在去操作IServerAgent了(當然,我們可以完全在IServerAgent的基礎上建構應用,而不關心IMessageTransceiver的存在)。當有消息發送/送出(無論是基本消息、功能請求消息、還是P2P消息)時,直接送出給IMessageTransceiver即可。IMessageTransceiver對要發送的消息采取如下流程:

(1)如果是非P2P消息,則直接送出給IServerAgent。

(2)如果是P2P消息,然後向p2PChannelManager查詢針對目标客戶的P2PChannel是否存在,如果存在,則直接通過P2PChannel發送;否則,就送出給IServerAgent進行轉發。

    以下是IMessageTransceiver實作這個流程的代碼:

        public NetMessage CommitRequest(NetMessage requestMsg, DataPriority dataPriority, bool checkRespond)

        {

            //通過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)。

    public interface IP2PChannelManager

        IP2PChannel GetP2PChannel(string destUserID) ;

    IP2PChannel,如其名,它是客戶與客戶之間P2P通信的信道的抽象,很顯然,目前最常用的P2P通道是基于UDP的NAT穿透的通道,這是IP2PChannelManager的實作之一。如果可能(比如不同的客戶位于同一區域網路内部),我們也可以在客戶之間使用基于Tcp 的P2P通道。IP2PChannel接口定義如下:

    public interface IP2PChannel

        void SendMessage(NetMessage msg) ;

    現在,使用ESFramework,我們可以在三個層次上建構你的用戶端應用:

(1)直接在NetworkStream或Socket上建構,這樣可以完全抛開ESFramework,但是這也需要你自己手動的處理所有麻煩的東西。

(2)在ITcpServerAgent上建構,這樣ESFramework會幫你做好所有消息的收發,請求與回複的比對,消息的優先級分類、消息的自動發送等等。

(3)在IMessageTransceiver建構,到這裡,你甚至不用關心你的P2P消息是通過P2PChannel直接發送的還是通過伺服器進行中轉的。底層的通信方式對于你的應用是透明的。

    在後面介紹NAPT穿透時,我會給出基于NAPT的IP2PChannel實作和對應的IMessageTransceiver實作。感謝關注!

<b></b><b></b>

<b></b>

<b></b> 

繼續閱讀