Search Unity

How to properly get the roundtrip time from a message?

Discussion in 'Multiplayer' started by rob_vld, Jul 23, 2015.

  1. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
    EDIT: Updated the code examples; same results

    How do i get the roundtrip time from an received message?

    The code below throws an "Wrong Operation" on error
    What am i doing wrong?

    Thank you.


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. using UnityEngine;
    6. using UnityEngine.Networking;
    7.  
    8. using System;
    9. using System.Linq;
    10. using System.Collections;
    11. using System.Collections.Generic;
    12.  
    13. public class MsgTimeStamp : MessageBase
    14.     {
    15.     public int timeStamp;
    16.     }
    17.  
    18. public class ManagerNetwork : MonoBehaviour
    19.     {
    20.     public GameObject prefabPlayer;
    21.  
    22.     public const short  MsgTypeServerTime = 1000;
    23.  
    24.     public byte         ChannelReliableSequenced;
    25.  
    26.     private void Start( )
    27.         {
    28.  
    29.         ConnectionConfig connectionConfig   = new UnityEngine.Networking.ConnectionConfig( );
    30.         ChannelReliableSequenced            = connectionConfig.AddChannel( QosType.ReliableSequenced );
    31.        
    32.         NetworkTransport.Init( );
    33.  
    34.         NetworkServer.Configure( connectionConfig, 5 );
    35.         NetworkServer.RegisterHandler( MsgType.Connect,     OnConnection_C );
    36.         NetworkServer.RegisterHandler( MsgTypeServerTime,   OnTimeTest_C );
    37.         NetworkServer.Listen( putNumberHere );
    38.  
    39.         }
    40.  
    41.     private void OnConnection_C( NetworkMessage networkMessage )
    42.         {
    43.         Debug.Log( "-------------------------------------------> OnConnection_C" );
    44.         var msgTimeStamp       = new MsgTimeStamp( );
    45.         msgTimeStamp.timeStamp = NetworkTransport.GetNetworkTimestamp( );
    46.         networkMessage.conn.SendByChannel( MsgTypeServerTime, msgTimeStamp, ChannelReliableSequenced );
    47.  
    48.         Debug.Log( "Sending timeStamp: " + msgTimeStamp.timeStamp );
    49.         }
    50.  
    51.     private void OnTimeTest_C( NetworkMessage networkMessage )
    52.         {
    53.         Debug.Log( "-------------------------------------------> OnTimeTest_C" );
    54.         var msgTimeStamp = networkMessage.ReadMessage<MsgTimeStamp>();
    55.         Debug.Log( "Received TimeStamp Message: " + msgTimeStamp.timeStamp );
    56.  
    57.         byte error;
    58.         int getRemoteDelayTimeMS = NetworkTransport.GetRemoteDelayTimeMS( networkMessage.conn.hostId
    59.                                                                         , networkMessage.conn.connectionId
    60.                                                                         , msgTimeStamp.timeStamp
    61.                                                                         , out error );
    62.         Debug.Log( "resultGetRemoteDelayTimeMS: " + getRemoteDelayTimeMS );
    63.         Debug.Log( "errorCode: " + Enum.GetName(typeof(NetworkError), error ));
    64.  
    65.         Debug.Log( "NetworkTransport.GetNetworkTimestamp( );" + NetworkTransport.GetNetworkTimestamp( ) );
    66.  
    67.         Debug.Log( "RTT: "+ NetworkTransport.GetCurrentRtt( networkMessage.conn.hostId, networkMessage.conn.connectionId, out error ) );
    68.  
    69.         Debug.Log( "errorCode: " + Enum.GetName(typeof(NetworkError), error ));
    70.         }
    71.     }
    72.  


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4. using System;
    5. using System.Collections;
    6. using System.Collections.Generic;
    7.  
    8. public class MsgTimeStamp : MessageBase
    9.     {
    10.     public int timeStamp;
    11.     }
    12.  
    13. public class ManagerNetwork : MonoBehaviour
    14.     {
    15.     private NetworkClient   networkClient;
    16.     private string          serverIP;
    17.     private int             serverPort;
    18.  
    19.     public const short      MsgTypeServerTime = 1000;
    20.  
    21.     public byte             ChannelReliableSequenced;
    22.  
    23.     private float           _serverTime;
    24.     private float           _serverTimeInit;
    25.  
    26.     private void Start( )
    27.         {
    28.         serverIP   = putStringHere;
    29.         serverPort = putNumberHere;
    30.  
    31.         ConnectionConfig connectionConfig   = new UnityEngine.Networking.ConnectionConfig( );
    32.         ChannelReliableSequenced            = connectionConfig.AddChannel( QosType.ReliableSequenced );
    33.        
    34.         NetworkTransport.Init( );
    35.  
    36.         networkClient = new NetworkClient();
    37.         networkClient.RegisterHandler( MsgType.Connect,     OnConnection_C );
    38.         networkClient.RegisterHandler( MsgTypeServerTime,   OnTimeTest_C );
    39.        
    40.         networkClient.Configure( connectionConfig, 1 );
    41.         networkClient.Connect( serverIP, serverPort );
    42.         }
    43.  
    44.     private void OnConnection_C( NetworkMessage networkMessage )
    45.         {
    46.         Debug.Log( "-------------------------------------------> OnConnection_C" );
    47.         var msgTimeStamp       = new MsgTimeStamp( );
    48.         msgTimeStamp.timeStamp = NetworkTransport.GetNetworkTimestamp( );
    49.         networkMessage.conn.SendByChannel( MsgTypeServerTime, msgTimeStamp, ChannelReliableSequenced );
    50.  
    51.         Debug.Log( "Sending timeStamp: " + msgTimeStamp.timeStamp );
    52.         }
    53.        
    54.     private void OnTimeTest_C( NetworkMessage networkMessage )
    55.         {
    56.         Debug.Log( "-------------------------------------------> OnTimeTest_C" );
    57.         var msgTimeStamp = networkMessage.ReadMessage<MsgTimeStamp>();
    58.         Debug.Log( "Received TimeStamp Message: " + msgTimeStamp.timeStamp );
    59.  
    60.         byte error;
    61.         int getRemoteDelayTimeMS = NetworkTransport.GetRemoteDelayTimeMS( networkMessage.conn.hostId
    62.                                                                         , networkMessage.conn.connectionId
    63.                                                                         , msgTimeStamp.timeStamp
    64.                                                                         , out error );
    65.         Debug.Log( "resultGetRemoteDelayTimeMS: " + getRemoteDelayTimeMS );
    66.         Debug.Log( "errorCode: " + Enum.GetName(typeof(NetworkError), error ));
    67.  
    68.         Debug.Log( "NetworkTransport.GetNetworkTimestamp( );" + NetworkTransport.GetNetworkTimestamp( ) );
    69.  
    70.         Debug.Log( "RTT: "+ NetworkTransport.GetCurrentRtt( networkMessage.conn.hostId, networkMessage.conn.connectionId, out error ) );
    71.  
    72.         Debug.Log( "errorCode: " + Enum.GetName(typeof(NetworkError), error ));
    73.         }
    74.     }
    75.  
     
    Last edited: Jul 24, 2015
  2. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
    i just tested it again with someone remote.... and added NetworkTransport.GetCurrentRtt( networkMessage.conn.hostId, networkMessage.conn.connectionId, out error )

    above remains the same, and the GetCurrentRtt was 0 with an ok on the error code

    (5.1.2p1)
     
  3. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @rob_vld hmm, it is not a problem of rtt delivery function, or getRemoteDelay function. The problem is that the server disconnected client by timeout as it has not received any messages from the client for a long time... Why? I don't know but probably it is a bug. Can you report it (with reproducing steps) and ping me with bug number, I will try to reproduce them

    thanks
    Alex
     
  4. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    Ok guys, just checked locally. Attached file contains code for server and client. Client send connect request and started send messages every frame. Server received messages and do not send back anything. I added clumsy to simulate latency. Everything works ...
     

    Attached Files:

  5. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
    Thank you for putting in the time to set up this advanced working demo!

    From your example i have learned that NetworkTransport.Init needs to be called before using it, however, adding this does not seem to differ. ( Updated the code above. )

    ---

    This short video is between 2 computers on a LAN: https://vid.me/qa81

    Q:
    There seems to be a "WrongOperation" on the server right after connection with the client, is this right; as this is what my example seems to give, on a single message?

    Q: Nearly no change on the client side concerning rtt and delay, is this to be expected?

    Q: Your demo seems to be all about the LLAPI... does this still apply to connecting with NetworkServer / Client?

    Q:
    The documentation on GetRemoteDelayTimeMS and GetCurrentRtt is very cryptic, what is actually the difference, and how should they be used, you seem to be using them in the same way in your demo?
     
    Last edited: Jul 24, 2015
  6. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
    @aabramychev

    I have done some more testing with an external network tool called Clumsy, this tool allows to simulate lag over the network/localHost

    Your demo shows a change on the client rtt, i am now able to "see" latency
    With my example however it remains 0

    Could there be a problem with how NetworkServer / NetworkClient establishes the connection then in combination with NetworkTransport or perhaps something does goes wrong with the first few packets sent?

    *Grasps some straws*
     
    Last edited: Jul 24, 2015
  7. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @rob_vld
    q: There seems to be a "WrongOperation" on the server...
    a: which operation? i will recheck
    q: Nearly no change on the client side concerning rtt and delay, is this to be expected?
    a: in lan without wifi yes.
    Q: Your demo seems to be all about the LLAPI...
    a: yes, should be, hlapi built on top of llapi, so all llapi function should work
    Q: The documentation on GetRemoteDelayTimeMS and GetCurrentRtt ...
    a: GetCurrentRTT will return averaged by last 8 probes rtt between llapi transport layers of communicated computers, it means that this value includes: transmitting time, waiting in incoming queue before reading, waiting in outgoing queue before sending. And it is not included the time for delivery message from user to llapi transport layer. Other words if you add timestamp to your message will send it to other peer and this peer will resend this message back. RTT which you will measure will contain GetCurrentRtt + time for waiting when you will pop this message + time for delivery from user to llapi network... and will be greater than GetCurrentRTT.

    GetRemoteDelayTimeMS() serves for time synchronization between peers. You can get timestamp (by GetNetworkTimestamp see example) and sign your message with them. When this message will arrive, receiver using GetRemoteDelayTimeMS function can understand delaying of this message (for example: this shoot was did 20ms ago...)..

    ==============
    Your last message.
    It should work. connection establishing, rtt, delay are llapi features and do not depend of hlapi. So if connection established for hlapi llapi connection will established too...

    I need your project (related to problem part only) to say more. "WrongOperation" most probably related that user asked host which doesn't exist, or connection which doesn't exist ...
     
  8. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
    @aabramychev

    So i have done some more testing and i have come to the conclusion that GetRemoteDelayTimeMS needs time to be initialized and therefore can not always be used right away...

    Q: Is this the case ?
    If yes, then there should really be another flag rather than "WrongOperation"
    If no, then there is a bug!

    Q: Is the outcome of GetRemoteDelayTimeMS a half round trip or a round trip ?
     
    Last edited: Jul 27, 2015
  9. rob_vld

    rob_vld

    Joined:
    Jul 9, 2013
    Posts:
    191
  10. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    GetRemoteDelayTimeMS returns delaying time - not rtt.
    Imagine that you have two computers. In time X, your pres button on the computer first, after 4 hours you send message on another computer where you say "In time X I presses button". GetRemoteDelayTimeMS(X) will return 4 hours.

    GetCurrentRTT will return rtt (not rtt/2) averaged by last 10 ping time periods. So if your ping timeout is 500 ms (default) it returns mean value of 10 pings or mean value in 5 sec...
     
  11. Deleted User

    Deleted User

    Guest

    Hello. May I ask for a bit of source code of implementation GetRemoteDelayTimeMS ?

    Thanks.
     
  12. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    ye sure, welcome to PM :)
     
  13. dnnkeeper

    dnnkeeper

    Joined:
    Jul 7, 2013
    Posts:
    84
    Unfortunately Unity 2017.3 got rid of old Network.Time method that worked flawlessly in 5.6 for determining exact time of sending a message. I have tried using GetRemoteDelayTimeMS but got weird results.

    To compare it with the Network.Time difference method I made a test project.

    When I connect from local to local machine I'm getting 10 - 40 ms by GetRemoteDelayTimeMS and ~0.000025 ms by Network.Time difference. On remote machine (WiFi LAN) I'm getting almost the same 13-40 ms by GetRemoteDelayTimeMS and solid 31 ms by Network.Time difference.

    Can you please explain the difference and recommend some method of achieving Network.Time synchronized across the network? It is crucial thing for smooth networking projects!

    ADDED: sorry, my bad. Network.Time difference is almost identical to GetRemoteDelayTimeMS and is about 30ms on local machine. Still looking for Network.Time workaround. Amost managed to sync it using Time.realtimeSinceStartup
     

    Attached Files:

    Last edited: Mar 23, 2018
  14. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @dnnkeeper take into account your frame rate and send rate... If your frame rate is 30FPS (or 30 ms per frame) and your latency is 0 ms, what's happened if you send message on the start of you frame but read on the end? It will exactly 30 ms. Make sense?
     
    dnnkeeper likes this.
  15. dnnkeeper

    dnnkeeper

    Joined:
    Jul 7, 2013
    Posts:
    84
    Thank you, it was exactly this :)
    I managed to sync server realtimeSinceStartup with network clients using GetRemoteDelayTimeMS at relatively good precision (one frame ~ deltaTime error). So now I can correctly compare and interpolate synchronized states values. It would be very handy to have such NetworkTime out of the box. I'll share my workaround but not sure of its reliability. For example I am getting GetRemoteDelayTimeMS == 0 in the first message sent to the new connection from NetworkServer.connections. Sending TimeSync message after 1 second after new connection was established works well but I doubt it is reliable.
     
    aabramychev likes this.
  16. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    it is because statistic has not ready yet. So couple of pings are required for rtt works correctly