Ağ istemci-sunucu mesaj değişimi ve saat senkronizasyonu yardımı


10

Masa hokeyi olan hızlı tempolu bir fizik oyunu yapıyorum. İki tokmak ve bir disk ile. Oyun iphone / ipad üzerinde çalışıyor ve GameCenter üzerinden çok oyunculu kısmı yapıyorum.

Ağ sistemi bu şekilde çalışır. Maçı yıldızlandıran müşteri, sunucu olarak kabul edilir ve maç talebini kabul eden müşteri istemcidir.

'Sunucu' fiziği çalıştırıyor ve yanıt anında ve müşteri de fiziği çalışıyor, böylece mesaj alışverişi arasında düzgün görünüyor. Ne sunucu olarak yapmak, istemciye benim puck hızı ve benim konum göndermek ve istemci onun puck hızı / senkronize tutmak için sunucu ile ilgili konumu ayarlar olmasıdır. Aksi takdirde fizik senkronize olmaz ve vidalar.

Ağ gecikmesi iyi olduğunda, 100 ms körük sonuçları oldukça iyidir, istemci tarafında pürüzsüz bir oynanabilir oyun var ve garip davranış minimumdur. Sorun, gecikme yaklaşık 150 ila 200 ms olduğunda ortaya çıkar. Bu durumda, istemcim disk zaten bir kenara ve ters yöne çarptı, ancak sunucudan bir gecikme mesajı alır ve biraz geri top davranışına garip bir duygu neden olur.

Bununla ilgili birkaç şey okudum:

Pong Ağı Örneği

Senkronizasyon Örneği'ni tıklayın

Clock Sync'te Wikipedia

Peki, bunu nasıl çözebilirim? Bildiğim en iyi seçeneği okuduğum kadarıyla zaman damgası ile sunucu / istemcide bir saat senkronizasyonu yapmak, böylece saatimle ilgili gecikme mesajları aldığımda, sadece görmezden gelip istemcilerin simülasyonunu yapmasına izin vermek iş. Buna katılıyor musunuz? Ve güvenilir olmayan veri gönderirken (UDP) gecikmeli mesajlar veya mesajlar bozuk olabilir.

Bu en iyi yaklaşımsa, saat senkronizasyonunu nasıl uygularım? Nasıl yapılacağı ile ilgili adımları okudum ama tam olarak anlamadım.

Diyor ki:

  1. İstemci geçerli yerel saati bir "zaman isteği" paketine damgalar ve sunucuya gönderir.
  2. Sunucu tarafından alındığında, sunucu sunucu zamanını damgalar ve geri döner
  3. İstemci tarafından alındığında, istemci gönderilen zamanı gönderilen süreden çıkarır ve hesaplama gecikmesini ikiye böler. İstemci-sunucu zaman deltasını belirlemek için geçerli zamanı sunucu zamanından çıkarır ve doğru saat deltasını elde etmek için yarı gecikmeyi ekler. (Şimdiye kadar bu algothim SNTP'ye çok benziyor)
  4. İstemci 1'den 3'e kadar olan adımları beş veya daha fazla kez tekrarlar ve her seferinde birkaç saniye duraklar. Arada başka trafiğe izin verilebilir, ancak en iyi sonuçlar için en aza indirilmelidir. Paket makbuzlarının sonuçları birikir ve en düşük gecikme ile en yüksek gecikme sırasına göre sıralanır. Ortalama gecikme süresi, bu sıralı listeden orta nokta örneği alınarak belirlenir.
  5. Medyandan yaklaşık 1 standart sapmanın üzerindeki tüm numuneler atılır ve kalan numunelerin ortalaması aritmetik bir ortalama kullanılarak alınır.

Bu örneği takip ederek bu olurdu:

Oyun yüklendi ve müşteri zamanım 0 şimdi gibi yapalım, bu yüzden sunucuya zamanım 0 gönderir.

İletiler sunucuya ulaşmak için 150ms sürer ancak sunucunun saati zaten başlamıştı ve istemciden 1 saniye ileridedir. Sunucu mesajı aldığında zaman: 1.15 olacak ve o zamanı istemciye gönderecek, biz iyi miyiz? Gecikmemizin 150 ms'de sabit olduğunu varsayalım.

Şimdi istemci zamanı 1.15 alır ve gönderilen zamanı gönderilen zamanı çıkarır ve hesaplama gecikmesini ikiye böler. Hangisi: 0.3 - 0 = 0.3 / 2 -> 150ms.

İstemci-sunucu zaman deltasını belirlemek için geçerli zamanı sunucu zamanından çıkarır ve doğru saat deltasını elde etmek için yarı gecikmeyi ekler:
İstemci zamanı: 0.3 Sunucu zamanı 1.15
0.3 - 1.15 = .85 + gecikme (.15) = 1

Bu nasıl senkronize edilir? Neyi kaçırıyorum?

Çok oyunculu ve ağ deneyiminde ilk kez, bu yüzden biraz kafam karıştı.

Teşekkür ederim.


İyi soru. Düzeltir misiniz: 0,3 - 1,15, 1,15 - 0,3?
Ciaran

Yanıtlar:


12

Gönderilen algoritma doğruydu, ancak örneğinizde sunucu paketinin istemciye ulaşması için geçen süreyi unutuyorsunuz, bu nedenle:

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

Gördüğünüz gibi, eğer müşteri saatini 1.15 olarak değiştirirse, sunucunun arkasında 0.15 olurdu, bu yüzden Ping için ayarlamanız gerekir (Gidiş-Dönüş Saati [RTT]). İşte birçok adımda yapılan tam delta zamanı hesaplaması:

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

Bu bize 1.00 saniyelik doğru delta süresini verir


Ben alıyorum, bu yüzden benim istemci saat 1.00 ve sunucu 1.30 i Sunucudan mesaj aldıktan sonra ben geç bir mesaj ya da bir şey olup olmadığını kontrol etmek için ping eklemek zorunda mı? Başka bir şey, ya gecikme değişirse, her zaman bu hesaplamaları yapmaya devam etmem gerekir mi?
gmemario

İstemcinin saatini sunucunun saatine eşit yapmak için geçerli saate 1.00s delta süresi eklenecektir. Gecikme her zaman değişiyor, her paketin biraz farklı bir RTT'si olacak. Bir oyunda olduğu gibi kısa bir zaman diliminde, bu zaman senkronizasyonunu sadece bir kez yapardım, müşteri sunucunun zamanının ne olduğu konusunda oldukça iyi bir tahmin yapacaktır ve her iki saat de yaklaşık aynı hızda ilerlemelidir. Sadece istisna, gelecekten gelmiş gibi görünen bir paket almanızdı. Bu durumda, 2 çözüm vardır: 1) Yeni bir zaman senkronizasyonu yapın. 2) Gelecekteki saati eşleştirmek için saatinizi ilerletin
John McDonald

Tamam, ben sadece emin olmak için bu duruma bakalım: Sunucu süresi: 1s İstemci süresi: 0s 150ms sunucuya almak Sunucu süresi: 1.15s İstemci süresi: 0.15s Sunucu istemciye almak için 1.15s 200ms istemci gönderir Yani, pingim şimdi 350 ms. Bu doğru mu? Sunucu süresi: 1.35 İstemci süresi: 0.35 Hesaplamaların yapılması: 1.15 - .35 + (0.35 - 0.00) / 2 Şimdi deltaTime = 0,975 Delta zamanı 0,975'i 0,35'ime eklersem şunu elde ederim: 1,325 Hangi tür desync. Bu doğru mu?
gmemario

@Gilson, Doğru. İki paket için gecikme süresi farklıysa (neredeyse garantili), istemcinin delta zamanı hesaplaması mükemmel olmaz. Müşterinin mükemmel olması için bir yol yoktur. Soruda tanımladığınız algoritmada, delta süresi birkaç kez hesaplandı ve bu sonuçların seçilmesi ve ortalamasının alınması için bir yöntem vardı. Çoğu zaman senkronizasyonu yöntemi böyle bir şey yapar, ancak genellikle borsalar gibi iş açısından kritik ve uzun süredir çalışan sunucular içindir. Kısa bir oyun için ihtiyaç duyduğunuz zaman doğruluğu için, bunun aşırıya kaçması olacağını düşünüyorum.
John McDonald

@Gilson, İstemci sunucunun zamanı hakkında makul bir kestirime sahip olduğu ve her iki saat de kabaca aynı oranda ilerlediği sürece, herhangi bir sorun fark etmemelisiniz. İstemci veya sunucu diğer tarafa bir eylem gönderdiğinde, yerel saatlerini gönderir. Alıcı tarafta, mesaj her zaman geçmişte olmalı ve geçmiş bir olay olarak yorumlanmalıdır. Bu, paketteki konum, hız (büyüklük + yön) ve zaman gibi tüm bilgilere ihtiyacınız olduğu anlamına gelir. Sonra diski oraya yerleştirebilir ve diski geçmişten bugüne taşıyabilirsiniz. Sohbet ediyorum btw
John McDonald
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.