ネットワーククライアントサーバーメッセージ交換とクロック同期ヘルプ


10

テーブルホッケーである高速の物理ゲームをやっています。マレット2つとパック1つ。ゲームはiphone / ipadで実行され、GameCenterを介してマルチプレイヤーの部分を実行しています。

これがネットワークシステムの動作方法です。マッチにスターを付けるクライアントはサーバーとして解決され、マッチリクエストを受け入れるのはクライアントです。

「サーバー」は物理演算を実行しており、応答は即時であり、クライアントも物理演算を実行しているため、メッセージ交換間でスムーズに見えます。私がサーバーとしてしていることは、パック速度と位置をクライアントに送信し、クライアントがサーバーに関連するパック速度/位置を調整してサーバーを同期させることです。そうしないと、物理が非同期になり、ねじ込みます。

ネットワークレイテンシが良好な場合、100ミリ秒以下の結果はかなり良好です。クライアント側でスムーズにプレイできるゲームが得られ、奇妙な動作は最小限です。ラグが約150〜200ミリ秒のときに問題が発生します。その場合、私のクライアントパックはすでにエッジと逆方向にヒットしていますが、サーバーから遅延メッセージを受信し、少し後ろに戻ってボールの動作に奇妙な感覚を引き起こしています。

私はそれについていくつか読んだ:

Pongネットワークの例

同期の例をクリックします

クロック同期に関するウィキペディア

だから、どうすればこれを解決できますか?私が持っている最良のオプションを読んだ限り、タイムスタンプを使用してサーバー/クライアントでクロック同期を行い、クロックに関連する遅延メッセージが表示された場合は無視して、クライアントのシミュレーションでジョブ。皆さんはそれに同意しますか?また、データを信頼できない(UDP)で送信しているため、メッセージが遅れたり、メッセージが乱れたりすることがあります。

それが最善のアプローチである場合、クロック同期をどのように実装しますか?手順を読みましたが、よくわかりませんでした。

それは言う:

  1. クライアントは現在の現地時間を「時間要求」パケットにスタンプし、サーバーに送信します。
  2. サーバーが受信すると、サーバーはサーバー時間にスタンプを付けて戻ります
  3. クライアントが受信すると、クライアントは送信時間から現在の時間を減算し、2で除算してレイテンシを計算します。サーバー時間から現在の時間を差し引いてクライアント/サーバー時間のデルタを決定し、待ち時間の半分を追加して正しいクロックデルタを取得します。(これまでのところ、このアルゴリズムはSNTPに非常に似ています)
  4. クライアントは、手順1〜3を5回以上繰り返し、そのたびに数秒停止します。他のトラフィックは暫定的に許可される可能性がありますが、最良の結果を得るために最小化する必要がありますパケット受信の結果は累積され、最小遅延から最大遅延の順にソートされます。待機時間の中央値は、この順序付きリストから中間点サンプルを選択することによって決定されます。
  5. 中央値からの標準偏差が約1を超えるすべてのサンプルは破棄され、残りのサンプルは算術平均を使用して平均化されます。

この例に従って、私はこれを持っています:

ゲームがロードされ、クライアントの時間が0になったふりをして、時間を0としてサーバーに送信します。

メッセージがサーバーに到達するまでに150ミリ秒かかりますが、サーバーのクロックは既に開始されており、クライアントより1秒進んでいます。サーバーがメッセージを受け取ると、時間は1.15になり、その時間をクライアントに送信します。ラグが150ミリ秒で一定であるとしましょう。

これで、クライアントは1.15の時間を受け取り、送信された時間から現在の時間を差し引き、レイテンシを計算するために2で割ります。Wichは、0.3-0 = 0.3 / 2-> 150msです。

サーバー時間から現在の時間を差し引いてクライアントサーバー時間のデルタを決定し、半分の待ち時間を追加して正しいクロックデルタを取得します。
クライアント時間:0.3サーバー時間1.15
0.3-1.15 = .85 +待ち時間(.15)= 1

それはどのように同期されますか?何が欠けていますか?

マルチプレイヤーとネットワークの経験が初めてなので、少し混乱しています。

ありがとうございました。


良い質問。あなたは修正できますか:0.3-1.15は1.15-0.3になりますか?
Ciaran 2012年

回答:


12

投稿されたアルゴリズムは正しかったですが、あなたの例では、サーバーパケットがクライアントに到達するのにかかる時間を忘れています。

Server time: 1
Client time: 0
Client sends 0 to server

... 150ms to get to server  (ping is 300! not 150ms in this case. Ping is round-trip)

Server time: 1.15
Client time: 0.15
Server receives packet and sends client 1.15

... 150ms to get back to client

Server time: 1.30
Client time: 0.30
Client receives 1.15 from server

ご覧のとおり、クライアントがクロックを1.15に変更した場合、サーバーより0.15遅れます。これが、Ping(往復時間[RTT])を調整する必要がある理由です。以下は、多くのステップで実行される完全なデルタ時間の計算です。

Server Time - Current Time + Ping / 2
= Server Time - Current Time + (Current Time - First Packet Time) / 2
= 1.15 (Perceived, not actual!) - 0.30 + (0.30 - 0.00) / 2
= 1.00

これにより、1.00秒の正しいデルタ時間が得られます。


私はそれを取得しているので、クライアントのクロックは1.00でサーバーは1.30です。サーバーからメッセージを受け取った後、pingを追加して遅延メッセージか何かを確認する必要がありますか?もう1つ、レイテンシが変化した場合、それらの計算を常に実行し続ける必要がありますか?
gmemario 2011年

1.00秒のデルタ時間を現在のクロックに追加して、クライアントの時間をサーバーの時間と等しくします。待ち時間は常に変化し、各パケットのRTTはわずかに異なります。ゲームのような短い時間枠では、この時間同期を1回だけ実行します。クライアントはサーバーの時刻をかなり正確に推測し、両方の時計がほぼ同じペースで進んでいるはずです。唯一の例外は、未来からのパケットを受け取った場合です。その場合、2つの解決策があります。1)新しい時刻同期を実行します。2)未来の時計に合わせて時計を進める
ジョンマクドナルド

わかりました。この状況を確認して、取得したことを確認します。サーバー時間:1秒クライアント時間:0秒サーバーに到達するための150ミリ秒サーバー時間:1.15秒クライアント時間:0.15秒サーバーは、クライアントに到達するために1.15秒200ミリ秒送信します。つまり、私のpingは350msです。あれは正しいですか?サーバー時間:1.35クライアント時間:0.35計算を行う:1.15-.35 +(0.35-0.00)/ 2今、deltaTime = 0,975を追加します。それも正しいですか?
gmemario 2011年

@ギルソン、それは正しい。2つのパケットのレイテンシが異なる(ほぼ保証されている)場合、クライアントのデルタ時間の計算は完全ではありません。クライアントが完璧になる方法はありません。質問で説明したアルゴリズムでは、デルタ時間は何度も計算され、これらの結果を選択して平均化する方法がありました。多くの時間同期メソッドはこのようなことを行いますが、通常、これらは証券取引所などのビジネスクリティカルで長時間実行されるサーバー用です。短いゲームに必要な時間の精度については、それはやりすぎだと思います。
ジョンマクドナルド

@ギルソン、クライアントがサーバーの時間の合理的な見積もりを持っていて、両方のクロックがほぼ同じ速度で進んでいる限り、問題に気付くべきではありません。クライアントまたはサーバーが反対側にアクションを送信すると、ローカル時刻が送信されます。受信側では、メッセージは常に過去である必要があり、過去のイベントとして解釈される必要があります。つまり、場所、速度(大きさ+方向)、時間など、パケット内のすべての情報が必要です。次に、パックをそこに配置し、パックを過去から現在に移動できます。私は今チャット中です
ジョンマクドナルド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.