The latest ESFramework/ESPlus version provides TCP and UDP-Based P2P channels, whether we use TCP-based P2P channels or UDP-Based P2P channels, ESPlus ensures that all P2P communication is reliable. This is because ESPlus re-encapsulates the TCP mechanism based on the original UDP to make UDP as reliable as TCP. In distributed systems (such as IM systems) that require high-frequency communication between clients, reliable P2P communication will save you huge bandwidth and server costs. For details, see ESFramework development manual (04)-reliable P2P and ESFramework usage tips-deploy P2P servers.
In ESFramework 4.0 (07), we introduced a common situation in which the client interacts with the server: the client sends a request message to the server, after the server completes processing, it returns a Response Message to the client. Another common case is that the client needs to send a message to another online user. Generally, such P2P messages are forwarded through the server. In many cases, there will be no major problems in transit, but for applications that require high-frequency and large-size message interaction such as video sessions and file transmission between users, all messages are transferred through the server, which greatly increases the pressure on the server. P2P channels are the most common solutions for this requirement. That is, messages that interact with users are sent through P2P channels.
I. P2P channel manager IP2PChannelManager
ESFramework uses ESFramework. Passive. IP2PChannelManager to manage all P2P channels. The IP2PChannelManager interface is defined as follows:
Public interface IP2PChannelManager
{
/// <Summary>
/// Whether the P2P channel to the target user is available.
/// </Summary>
/// <Param name = "destUserID"> Target User ID </param>
Bool P2PChannelUsable (string destUserID );
/// <Summary>
/// Send messages through P2PChannel.
/// </Summary>
/// <Param name = "destUserID"> Target User ID </param>
/// <Param name = "msg"> message to be sent </param>
/// <Param name = "datemediority"> priority of sending </param>
Void SendMessage (string destUserID, IMessage msg, datemediority );
}
If the application does not require P2P channels, you can directly use the ESFramework. Passive. EmptyP2PChannelManager class in the null object Mode.
The most common method to implement P2P channels is P2P penetration, while ESPlus provides a ready-to-use TCP-based P2P channel manager ESPlus. application. p2PSession. passive. tcp. tcpChannelManager and UDP-Based P2P channel manager ESPlus. application. p2PSession. passive. udp. udpChannelManager is for our use. However, it is not easy to use. To successfully deploy P2P applications, you also need to deploy NAPT servers and P2P servers to support P2P penetration and establishment of P2P channels. These are not the core content of ESFramework.
If you can implement your own P2P channel (such as UPnP-based), you only need to implement the IP2PChannelManager interface and connect it to MessageTransceiver.
II.Message transceiver IMessageTransceiver
ESFramework uses ESFramework. passive. IMessageTransceiver is used to support the connection of P2P channels. IMessageTransceiver is mainly used to shield users from P2P messages transmitted through servers or through P2P channels, this makes the underlying channel selection transparent to upper-layer application developers.
The IMessageTransceiver interface is defined as follows:
Public interface IMessageTransceiver
{
IP2PChannelManager P2PChannelManager {set ;}
IServerAgent ServerAgent {set ;}
IContractHelper ContractHelper {set ;}
Ireeclipsemanager ResponseManager {set;} IMessagePipe MessagePipe {set ;}
/// <Summary>
/// Submit data.
/// (1) if the message is not a P2P message, it is directly submitted to the server.
/// (2) if the message is P2P (that is, the recipient is another online user) and the P2PChannel of the target user is available, it is sent to the user through P2PChannel. Otherwise, the request is submitted directly to the server.
/// </Summary>
/// <Param name = "msg"> message to be submitted </param>
/// <Param name = "datemediority"> priority of message sending </param>
Void CommitRequest (IMessage msg, datemediority );
/// <Summary>
/// Submit the data and return a response. If resMessageType is not null and no response is returned after timeout, a timeout exception is thrown.
/// (1) If datemediority! = Datemediority. CanBeDiscarded, resMessageType can only be null.
/// (2) if the message is not a P2P message, it is directly submitted to the server.
/// (3) if the message is P2P (that is, the recipient is another online user) and the P2PChannel of the target user is available, it is sent to the user through P2PChannel. Otherwise, the request is submitted directly to the server.
/// </Summary>
/// <Param name = "msg"> message to be submitted </param>
/// <Param name = "datemediority"> priority of message sending </param>
/// <Param name = "resMessageType"> type of the expected response message </param>
/// <Returns> Response Message </returns>
IMessage CommitRequest (IMessage msg, datemediority, int? ResMessageType );
/// <Summary>
/// Submit data to the server. Even if the message is P2P and the P2P channel is available, the message must pass through the server.
/// </Summary>
/// <Param name = "requestMsg"> message to be submitted </param>
/// <Param name = "datemediority"> priority of message sending </param>
/// <Param name = "resMessageType"> type of the expected response message </param>
/// <Returns> Response Message </returns>
IMessage CommitRequestToServer (IMessage requestMsg, datemediority, int? ResMessageType );
}
(1) When the Message Receiver (IMessage. header. when DestUserID is another online user, MessageTransceiver first checks whether a P2P channel is available. If yes, it is directly sent to IP2PChannelManager; otherwise, it is sent to the server through IServerAgent.
(2) If the message receiver is the server, the message is submitted directly to the server through the IServerAgent.
(3) If the message is a request message and needs to be answered, the second CommitRequest method is used. Note that the request message may be processed by the server or another online client, depending on whether the message receiver (IMessage. Header. DestUserID) is a server or another online user.
(4) For some types of P2P messages, our project may need this message to pass through the server. Even if the corresponding P2P channel exists, it must also pass through (for example, messages to be recorded by the server), you can directly call the CommitRequestToServer method at this time.
(5) IMessageTransceiver depends on IMessagePipe because the message skeleton process must be followed before being sent through a P2P channel.
(6) Why does IMessageTransceiver rely on the reply manager ireeclipsemanager? This is because when a request message is sent through a P2P channel, IServerAgent does not need to be called, therefore, MessageTransceiver needs to extract matched reply messages from the reply manager.
From the client perspective, we can see that the process from IRegularSender to IServerAgent and then to IMessageTransceiver is a step-by-step enhancement process, and the implementation of the next component is built on the previous component. IRegularSender solves the problem that the sent message must pass through MessagePipe. IServerAgent supports synchronous message calling, while IMessageTransceiver shields the underlying message sending channel from the user.
Another point to note is that the peer-to-peer channel receiver can directly deliver the received messages to MessageDispatcher for dispatching and processing. In this way, our message processing skeleton process is reused.
Iii. Demo code
In client programming and development, it is best to use IMessageTransceiver instead of IRegularSender or IServerAgent to send messages. It doesn't matter even if P2P channels are not used for the time being. If you need to start P2P channels in the future, the Code does not need to be modified. You only need to use the formal P2P channel manager object in the configuration file to replace EmptyP2PChannelManager.
Finally, we construct an IMessageTransceiver instance:
IContractHelper contractHelper = ......;
Ireeclipsemanager responseManager = ......;
IServerAgent serverAgent = ......;
IMessageTransceiver messageTransceiver = new MessageTransceiver ();
MessageTransceiver. ContractHelper = contractHelper;
MessageTransceiver. P2PChannelManager = new EmptyP2PChannelManager ();
MessageTransceiver. ResponseManager = responseManager;
MessageTransceiver. ServerAgent = serverAgent;
// IMessage response = messageTransceiver. CommitRequest (requestMessage, datemediority. Common, 102 );
ESFramework 4.0 Overview
What are the advantages of ESFramework 4.0?
ESFramework 4.0 upgrade description (continuous update)
All articles in ESFramework 4.0 Quick Start
All articles in ESFramework 4.0 advanced edition Series