P2P direct connection? Transfer via server?

Source: Internet
Author: User

When two clients A and B of the same system send messages to each other, if there is A P2P channel between them, there are two message transmission paths: directly transmitted through P2P channels or through servers. As shown in:

Generally, for applications, if A P2P channel can be successfully created (that is, A hole is successful), all messages between A and B will go through the P2P channel directly, this can effectively save the server bandwidth and reduce the server load. This model is the so-called "P2P channel first" model and the simplest channel selection model.

I. Channel Quality Priority Model

However, some systems may not be able to handle such A simple process. In the simplest example, if some types of messages transmitted between A and B must be monitored by the server, such a message must pass through the server. Next, we will discuss a complicated situation. For example, in a network speech conversation system, the channel quality directly determines the quality of user experience. We hope that in such a system, voice data must always be transmitted through the channel with higher quality in the two channels. This is the so-called "channel quality first" model.

The "channel quality first" model is easy to understand, but it is still difficult to implement it in practice. There are usually two implementation methods:

(1) Timing detection and comparison of channel latency, and automatic channel switching.

(2) The upper-layer application determines when to switch the channel. Generally, when the application finds that the currently used channel does not meet the requirements, it proactively requests to switch to another channel.

Ii. Model Implementation

Next, we will implement these two methods based on the communication functions provided by ESFramework. We use the AgileP2PCustomizeOutter class to encapsulate it and use Attribute control to enable this method.

Public class AgileP2PCustomizeOutter: IEngineActor {// dictionary. UserID-the currently selected channel (if it is true, it indicates a P2P channel; otherwise, it is transferred through the server )? Private ObjectManager <string, bool> channelStateManager = new ObjectManager <string, bool> (); private ICustomizeOutter customizeOutter; // message sender private IP2PController p2PController; // P2P controller private IBasicOutter basicOutter; // heartbeat transmitter private AgileCycleEngine agileCycleEngine; // timed detection engine # region PingTestSpanInSecs private int pingTestSpanInSecs = 60; /// <summary> /// the interval between timed ping tests and automatic switch channels. Unit: seconds. The default value is 60. /// If it is set to be less than or equal to 0, it indicates that the ping test is not performed regularly and the channel will not be automatically switched. /// </Summary> public int PingTestSpanInSecs {get {return response;} set {response = value ;}# endregion # region Initialize public void Initialize (ICustomizeOutter _ customizeOutter, IP2PController _ p2PController, IBasicOutter _ basicOutter) {this. customizeOutter = _ customizeOutter; this. p2PController = _ p2PController; this. basicOutter = _ basicOutter; this. p2PController. p2 PChannelOpened + = new ESBasic. cbGeneric <P2PChannelState> (p2PController_P2PChannelOpened); this. p2PController. p2PChannelClosed + = new ESBasic. cbGeneric <P2PChannelState> (p2PController_P2PChannelClosed); this. p2PController. allP2PChannelClosed + = new ESBasic. cbGeneric (p2PController_AllP2PChannelClosed); Dictionary <string, P2PChannelState> dic = this. p2PController. getP2PChannelState (); foreach (P2PChan NelState state in dic. values) {bool p2pFaster = this. testSpeed (state. destUserID); this. channelStateManager. add (state. destUserID, p2pFaster);} if (this. pingTestSpanInSecs> 0) {this. agileCycleEngine = new AgileCycleEngine (this); this. agileCycleEngine. detectSpanInSecs = this. pingTestSpanInSecs; this. agileCycleEngine. start () ;}// scheduled execution. select public bool EngineAction () {foreach (stri) as the channel between the current client and other clients. Ng userID in this. channelStateManager. getKeyList () {bool p2pFaster = this. testSpeed (userID); this. channelStateManager. add (userID, p2pFaster);} return true;} void p2PController_AllP2PChannelClosed () {this. channelStateManager. clear ();} void p2PController_P2PChannelClosed (P2PChannelState state) {this. channelStateManager. remove (state. destUserID);} void p2PController_P2PChannelOpened (P2PChannel State state) {bool p2pFaster = this. testSpeed (state. destUserID); this. channelStateManager. add (state. destUserID, p2pFaster) ;}# endregion # region TestSpeed /// <summary> // timed test /// </summary> private bool TestSpeed (string userID) {try {int transfer = this. basicOutter. pingByServer (userID); int p2p = this. basicOutter. pingByP2PChannel (userID); return p2p <= transfer;} catch (Exception ee) {retu Rn false ;}# endregion /// <summary> /// manually switch the channel. /// </Summary> public void SwitchChannel (string destUserID) {if (this. channelStateManager. contains (destUserID) {bool p2p = this. channelStateManager. get (destUserID); this. channelStateManager. add (destUserID ,! P2p) ;}//< summary> /// determines whether the target user uses a P2P channel. /// </Summary> public bool IsUsingP2PChannel (string destUserID) {return this. channelStateManager. get (destUserID);} public bool IsExistP2PChannel (string destUserID) {return this. channelStateManager. contains (destUserID) ;}/// <summary> /// send information to online users. /// </Summary> /// <param name = "targetUserID"> Target User ID for receiving messages. </Param> /// <param name = "informationType"> Custom information type </param> /// <param name = "post"> whether to send messages in Post Mode </param> // <param name = "action"> action taken when the channel is busy </param> public void Send (string targetUserID, int informationType, byte [] info, bool post, ActionTypeOnChannelIsBusy action) {bool p2pFaster = this. channelStateManager. get (targetUserID); ChannelMode mode = p2pFaster? ChannelMode. byP2PChannel: ChannelMode. transferByServer; this. customizeOutter. send (targetUserID, informationType, info, post, action, mode) ;}/// <summary> // Send large data block information to online users or servers. This method will not be returned until the data is sent. If you are worried about blocking the calling thread for a long time, consider calling this method asynchronously. /// </Summary> /// <param name = "targetUserID"> Target User ID for receiving messages. If it is null, the receiver is the server. </Param> /// <param name = "informationType"> Custom information type </param> /// <param name = "blobInfo"> large data block Information </param> // <param name = "fragmentSize">, fragment Size </param> public void SendBlob (string targetUserID, int informationType, byte [] blobInfo, int fragmentSize) {bool p2pFaster = this. channelStateManager. get (targetUserID); ChannelMode mode = p2pFaster? ChannelMode. ByP2PChannel: ChannelMode. TransferByServer; this. customizeOutter. SendBlob (targetUserID, informationType, blobInfo, fragmentSize, mode );}}

Now, let's briefly explain the above implementation.

(1) because the current client may communicate with multiple other clients, there is a problem of channel selection for communication with each other client, therefore, you need a dictionary ObjectManager to manage them.

(2) When a P2P channel is successfully created, ping and compare it for the first time and record the result to the dictionary.

(3) The timing engine checks and compares the channels of each other client every 60 seconds, and automatically selects the channel with a small ping value.

(4) When we set PingTestSpanInSecs to 0, we can use the SwitchChannel method to manually switch the channel, that is, the above method 2 is implemented.

(5) Our ultimate goal is to implement the Send and SendBlob methods. Then we can use the AgileP2PCustomizeOutter class to replace ICustomizeOutter to Send messages.

Iii. Method Selection

The above two implementation methods of the "channel quality first" model are described. How can we choose the "channel quality first" Model in actual application?

1. ping detection comparison, automatic switch

In this way, the drawback is that ping detection may be very inaccurate or even incorrect in a system that requires high-frequency communication between clients.

For example, in a real-time video conversation system, the bandwidth requirement is relatively high. Assuming that all the video data is in the P2P channel, the P2P channel is very busy, the transfer channel via the server is almost idle. Therefore, when a scheduled ping is detected, the ping value of the P2P channel is greater than the actual ping value. This leads to misjudgment and automatic failover.

2. Manual Switch

For the video conversation example, manual switching may be a better choice. The application determines whether to switch the channel based on the actual effect of the upper layer. For example, in a video conversation system, an application can regularly provide feedback based on the information receiver (the number of audio/video packets is missing within a period of time, to determine whether to switch to another channel. This method is more concise and can be expressed as follows: if the current channel quality has reached the application requirements, no switchover will be performed even if the other channel is faster and more stable; if the current channel quality does not meet the application requirements, switch to another channel (the quality of another channel may be worse ).

This article is just a simple introduction to the channel selection model. In fact, this problem is quite complicated, especially in some projects with high communication requirements, it would be more difficult to consider the channel model of broadcast messages. If you are interested, you can leave a message for further discussion.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.