mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
feature: NetworkConnectionToClient.rtt via Ping & Pong Messages (#3545)
* NetworkConnectionToClient: send Ping message every PingFrequency * breaking: NetworkPing/PongMessage .clientTime renamed to .localTime because it'll be used in both directions * Server->Client->Server Ping/Pong messages and rtt * don't ping in host mode * adjust tests * TODO
This commit is contained in:
parent
398d2e6d2c
commit
483006eadc
@ -29,6 +29,9 @@ internal override void Send(ArraySegment<byte> segment, int channelId = Channels
|
||||
// true because local connections never timeout
|
||||
internal override bool IsAlive(float timeout) => true;
|
||||
|
||||
// don't ping host client in host mode
|
||||
protected override void UpdatePing() {}
|
||||
|
||||
internal void DisconnectInternal()
|
||||
{
|
||||
// set not ready and handle clientscene disconnect in any case
|
||||
|
@ -111,22 +111,21 @@ public struct EntityStateMessage : NetworkMessage
|
||||
public ArraySegment<byte> payload;
|
||||
}
|
||||
|
||||
// A client sends this message to the server
|
||||
// to calculate RTT and synchronize time
|
||||
// whoever wants to measure rtt, sends this to the other end.
|
||||
public struct NetworkPingMessage : NetworkMessage
|
||||
{
|
||||
public double clientTime;
|
||||
public double localTime;
|
||||
|
||||
public NetworkPingMessage(double value)
|
||||
{
|
||||
clientTime = value;
|
||||
localTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
// The server responds with this message
|
||||
// The client can use this to calculate RTT and sync time
|
||||
// the other end responds with this message.
|
||||
// we can use this to calculate rtt.
|
||||
public struct NetworkPongMessage : NetworkMessage
|
||||
{
|
||||
public double clientTime;
|
||||
public double localTime;
|
||||
}
|
||||
}
|
||||
|
@ -471,6 +471,7 @@ internal static void RegisterMessageHandlers(bool hostMode)
|
||||
RegisterHandler<ObjectDestroyMessage>(OnObjectDestroy);
|
||||
RegisterHandler<ObjectHideMessage>(OnObjectHide);
|
||||
RegisterHandler<NetworkPongMessage>(NetworkTime.OnClientPong, false);
|
||||
RegisterHandler<NetworkPingMessage>(NetworkTime.OnClientPing, false);
|
||||
RegisterHandler<SpawnMessage>(OnSpawn);
|
||||
RegisterHandler<ObjectSpawnStartedMessage>(OnObjectSpawnStarted);
|
||||
RegisterHandler<ObjectSpawnFinishedMessage>(OnObjectSpawnFinished);
|
||||
|
@ -46,6 +46,14 @@ public class NetworkConnectionToClient : NetworkConnection
|
||||
// Snapshot Buffer size limit to avoid ever growing list memory consumption attacks from clients.
|
||||
public int snapshotBufferSizeLimit = 64;
|
||||
|
||||
// ping for rtt (round trip time)
|
||||
// useful for statistics, lag compensation, etc.
|
||||
double lastPingTime = 0;
|
||||
internal ExponentialMovingAverage _rtt = new ExponentialMovingAverage(NetworkTime.PingWindowSize);
|
||||
|
||||
/// <summary>Round trip time (in seconds) that it takes a message to go server->client->server.</summary>
|
||||
public double rtt => _rtt.Value;
|
||||
|
||||
public NetworkConnectionToClient(int networkConnectionId)
|
||||
: base(networkConnectionId)
|
||||
{
|
||||
@ -175,12 +183,29 @@ internal void BufferRpc(RpcMessage message, int channelId)
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdatePing()
|
||||
{
|
||||
// localTime (double) instead of Time.time for accuracy over days
|
||||
if (NetworkTime.localTime >= lastPingTime + NetworkTime.PingInterval)
|
||||
{
|
||||
// TODO it would be safer for the server to store the last N
|
||||
// messages' timestamp and only send a message number.
|
||||
// This way client's can't just modify the timestamp.
|
||||
NetworkPingMessage pingMessage = new NetworkPingMessage(NetworkTime.localTime);
|
||||
Send(pingMessage, Channels.Unreliable);
|
||||
lastPingTime = NetworkTime.localTime;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
// send rpc buffers
|
||||
FlushRpcs(reliableRpcs, Channels.Reliable);
|
||||
FlushRpcs(unreliableRpcs, Channels.Unreliable);
|
||||
|
||||
// ping client for rtt
|
||||
UpdatePing();
|
||||
|
||||
// call base update to flush out batched messages
|
||||
base.Update();
|
||||
}
|
||||
|
@ -266,6 +266,7 @@ internal static void RegisterMessageHandlers()
|
||||
RegisterHandler<ReadyMessage>(OnClientReadyMessage);
|
||||
RegisterHandler<CommandMessage>(OnCommandMessage);
|
||||
RegisterHandler<NetworkPingMessage>(NetworkTime.OnServerPing, false);
|
||||
RegisterHandler<NetworkPongMessage>(NetworkTime.OnServerPong, false);
|
||||
RegisterHandler<EntityStateMessage>(OnEntityStateMessage, true);
|
||||
RegisterHandler<TimeSnapshotMessage>(OnTimeSnapshotMessage, true);
|
||||
}
|
||||
|
@ -109,15 +109,16 @@ internal static void UpdateClient()
|
||||
}
|
||||
}
|
||||
|
||||
// client rtt calculation //////////////////////////////////////////////
|
||||
// executed at the server when we receive a ping message
|
||||
// reply with a pong containing the time from the client
|
||||
// and time from the server
|
||||
internal static void OnServerPing(NetworkConnectionToClient conn, NetworkPingMessage message)
|
||||
{
|
||||
// Debug.Log($"OnPingServerMessage conn:{conn}");
|
||||
// Debug.Log($"OnServerPing conn:{conn}");
|
||||
NetworkPongMessage pongMessage = new NetworkPongMessage
|
||||
{
|
||||
clientTime = message.clientTime,
|
||||
localTime = message.localTime,
|
||||
};
|
||||
conn.Send(pongMessage, Channels.Unreliable);
|
||||
}
|
||||
@ -128,8 +129,32 @@ internal static void OnServerPing(NetworkConnectionToClient conn, NetworkPingMes
|
||||
internal static void OnClientPong(NetworkPongMessage message)
|
||||
{
|
||||
// how long did this message take to come back
|
||||
double newRtt = localTime - message.clientTime;
|
||||
double newRtt = localTime - message.localTime;
|
||||
_rtt.Add(newRtt);
|
||||
}
|
||||
|
||||
// server rtt calculation //////////////////////////////////////////////
|
||||
// Executed at the client when we receive a ping message from the server.
|
||||
// in other words, this is for server sided ping + rtt calculation.
|
||||
// reply with a pong containing the time from the server
|
||||
internal static void OnClientPing(NetworkPingMessage message)
|
||||
{
|
||||
// Debug.Log($"OnClientPing conn:{conn}");
|
||||
NetworkPongMessage pongMessage = new NetworkPongMessage
|
||||
{
|
||||
localTime = message.localTime,
|
||||
};
|
||||
NetworkClient.Send(pongMessage, Channels.Unreliable);
|
||||
}
|
||||
|
||||
// Executed at the server when we receive a Pong message back.
|
||||
// find out how long it took since we sent the Ping
|
||||
// and update time offset
|
||||
internal static void OnServerPong(NetworkConnectionToClient conn, NetworkPongMessage message)
|
||||
{
|
||||
// how long did this message take to come back
|
||||
double newRtt = localTime - message.localTime;
|
||||
conn._rtt.Add(newRtt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ public void Send_BatchesUntilUpdate()
|
||||
{
|
||||
// create connection and send
|
||||
NetworkConnectionToClient connection = new NetworkConnectionToClient(42);
|
||||
NetworkTime.PingInterval = float.MaxValue; // disable ping for this test
|
||||
byte[] message = {0x01, 0x02};
|
||||
connection.Send(new ArraySegment<byte>(message));
|
||||
|
||||
@ -63,6 +64,7 @@ public void SendBatchingResetsPreviousWriter()
|
||||
|
||||
// create connection
|
||||
NetworkConnectionToClient connection = new NetworkConnectionToClient(42);
|
||||
NetworkTime.PingInterval = float.MaxValue; // disable ping for this test
|
||||
|
||||
// send and update big message
|
||||
byte[] message = {0x01, 0x02};
|
||||
|
Loading…
Reference in New Issue
Block a user