これは6歳なので、ちょっとした降霊術ですが、ネットワークゲームでも同様の問題に対処する必要がありました。
すぐに明らかになる理由から、私が「マルコポーロ」と呼んだテクニックを採用しました。メッセージを交換できるようにするには2つのクロックが必要であり、その精度は、メッセージを交換できる速度に依存します。
免責事項:私はこれを最初に行うのではなく、これが2つのクロックを同期するための最も基本的な方法であると確信しています。それでも、文書化された方法は見つかりませんでした。
クロックB(同期しようとしているクロック)では、次のことを行います::
// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;
// Send that to clock A
SendSyncRequest();
// Wait for an answer
Sleep(..);
クロックA(基準クロック)には、次のハンドラーがあります::
// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
// We received "Marco" - Send "Polo"
SendSyncReply(DateTime.UtcNow);
}
そして時計Bに戻る::
// This is triggered by SendSyncReply
OnReceiveSyncReply(DateTime remoteHalfTime)
{
// Log the time we received it
DateTime localTime_Polo_Receive = DateTime.UtcNow;
// The remote time is somewhere between the two local times
// On average, it will be in the middle of the two
DateTime localHalfTime = localTime_Marco_Send +
(localTime_Polo_Receive - localTime_Marco_Send) / 2;
// As a result, the estimated dT from A to B is
TimeSpan estimatedDT_A_B = localHalfTime - remoteHalfTime;
}
その結果、現在の現地時間から差し引いてリモート時間を見積もることができる、気の利いたTimeSpanにアクセスできるようになりました。
DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;
この見積もりの精度は、send-receive-send-receiveのラウンドトリップ時間の影響を受けます。また、クロックドリフトも考慮する必要があります(これは複数回行う必要があります)。
- 往復時間。瞬時であれば、正確なdTが得られます。戻ってくるのに1秒かかる場合、遅延が送信側にあるのか受信側にあるのかわかりません。その結果、エラーは0 <e <RTTになり、平均してRTT/2になります。送信(または受信)に他の時間よりも時間がかかることがわかっている場合は、それを活用してください。受信した時間はハーフタイムではありませんが、各レッグにかかる時間に比例してシフトします。
- クロックドリフト。CPUクロックはドリフトし、おそらく1日あたり1秒です。したがって、潜在的なドリフトが重要な役割を果たす可能性がある場合は、もう一度ポーリングしてください。