Pertukaran pesan klien-server jaringan dan bantuan sinkronisasi jam

10

Saya sedang melakukan permainan fisika serba cepat yang merupakan hoki meja. Dengan dua palu dan satu keping. Game ini berjalan di iphone / ipad dan saya melakukan bagian multiplayer melalui GameCenter.

Beginilah cara sistem jaringan bekerja. Klien yang membintangi pertandingan, akan ditetapkan sebagai server dan yang menerima permintaan pertandingan adalah klien.

'Server' memiliki fisika berjalan dan responsnya segera dan klien juga memiliki fisika mereka berjalan sehingga terlihat mulus di antara pertukaran pesan. Apa yang saya lakukan sebagai server, adalah bahwa saya mengirim ke klien kecepatan keping saya dan posisi saya dan klien menyesuaikan kecepatan kepingnya / posisi yang terkait dengan server untuk tetap menyelaraskannya. Jika tidak, fisika akan tidak sinkron dan mengacaukannya.

Ketika latensi jaringan baik, di bawah 100ms hasilnya cukup bagus, saya mendapat permainan yang lancar dimainkan di sisi klien dan perilaku aneh minimum. Masalahnya terjadi ketika lag sekitar 150 hingga 200 ms. Dalam hal itu, kebetulan bahwa keping klien saya sudah mengenai sisi yang terbalik dan terbalik tetapi ia menerima pesan penundaan dari server dan itu sedikit mundur menyebabkan perasaan aneh pada perilaku bola.

Saya sudah membaca beberapa hal tentang itu:

Contoh Jaringan Pong

Klik Contoh Sinkronisasi

Wikipedia pada Sinkronisasi Jam

Jadi, bagaimana saya bisa menyelesaikan ini? Sejauh yang saya baca opsi terbaik yang saya miliki adalah melakukan sinkronisasi jam di server / klien dengan timestamp sehingga ketika saya mendapatkan pesan penundaan terkait jam saya, saya abaikan saja dan biarkan simulasi klien melakukan pekerjaan. Apakah kalian setuju dengan itu? Dan karena saya mengirim data tidak dapat diandalkan (UDP) saya mungkin mendapatkan pesan tertunda atau pesan rusak.

Jika itu adalah pendekatan terbaik, bagaimana cara menerapkan sinkronisasi jam. Saya sudah membaca langkah-langkah tentang bagaimana tetapi saya tidak cukup memahaminya.

Dikatakan bahwa:

  1. Klien mencap waktu lokal saat ini pada paket "permintaan waktu" dan mengirim ke server.
  2. Setelah diterima oleh server, server akan mencap waktu server dan kembali
  3. Setelah diterima oleh klien, klien mengurangi waktu saat ini dari waktu yang dikirim dan membaginya dengan dua untuk menghitung latensi. Ini mengurangi waktu saat ini dari waktu server untuk menentukan delta waktu client-server dan menambahkan setengah-latensi untuk mendapatkan delta jam yang benar. (Sejauh ini algothim ini sangat mirip dengan SNTP)
  4. Klien mengulangi langkah 1 hingga 3 lima kali atau lebih, berhenti beberapa detik setiap kali. Lalu lintas lain mungkin diizinkan untuk sementara, tetapi harus diminimalkan untuk hasil terbaik. Hasil penerimaan paket diakumulasikan dan diurutkan dalam latensi terendah hingga latensi tertinggi. Median latensi ditentukan dengan memilih sampel titik tengah dari daftar yang dipesan ini.
  5. Semua sampel di atas sekitar 1 standar-deviasi dari median dibuang dan sisa sampel rata-rata menggunakan rata-rata aritmatika.

Mengikuti contoh ini saya akan memiliki ini:

Mari kita berpura-pura permainan telah dimuat dan waktu klien saya adalah 0 sekarang, jadi saya kirim ke server bahwa waktu saya adalah 0.

Pesan membutuhkan 150ms untuk sampai ke server tetapi jam server sudah dimulai dan 1 detik di depan klien. Ketika server menerima pesan, waktunya akan menjadi: 1.15 dan mengirimkan waktu itu ke klien, apakah kita baik-baik saja? Mari kita berpura-pura lag kita konstan pada 150 ms.

Sekarang klien menerima waktu 1,15 dan mengurangi waktu saat ini dari waktu yang dikirim dan membaginya menjadi dua untuk menghitung latensi. Wich adalah: 0,3 - 0 = 0,3 / 2 -> 150ms.

Ini mengurangi waktu saat ini dari waktu server untuk menentukan delta waktu klien-server dan menambahkan setengah-latensi untuk mendapatkan delta jam yang benar:
Waktu klien: 0,3 Waktu server 1,15
0,3 - 1,15 = 0,85 + latensi (0,15) = 1

Bagaimana itu disinkronkan? Apa yang saya lewatkan?

Ini pertama kalinya saya mengalami multipemain dan pengalaman jaringan, jadi saya agak bingung.

Terima kasih.

gmemario
sumber
Pertanyaan bagus. Bisakah Anda mengoreksi: 0,3 - 1,15 menjadi 1,15 - 0,3?
Ciaran

Jawaban:

12

Algoritma yang dipasang benar, tetapi dalam contoh Anda, Anda lupa tentang waktu yang dibutuhkan untuk paket server untuk sampai ke klien, jadi:

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

Sekarang seperti yang Anda lihat, jika klien mengubah jam ke 1,15, itu akan menjadi 0,15 di belakang server, inilah mengapa Anda harus menyesuaikan untuk Ping (alias Round Trip Time [RTT]). Berikut ini perhitungan waktu delta penuh yang dilakukan pada banyak langkah:

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

Ini memberi kita waktu delta yang benar yaitu 1,00 detik

John McDonald
sumber
Saya mendapatkannya, jadi jam klien saya adalah 1,00 dan server adalah 1,30 Setelah saya mendapatkan pesan dari server, apakah saya harus menambahkan ping untuk memeriksa apakah ada pesan terlambat atau sesuatu? Hal lain, bagaimana jika latensi berubah, apakah saya harus terus melakukan calcs itu sepanjang waktu?
gmemario
Waktu delta 1,00 harus ditambahkan ke jam saat ini untuk membuat waktu klien sama dengan waktu server. Latensi selalu berubah, setiap paket akan memiliki RTT yang sedikit berbeda. Dalam jangka waktu pendek seperti dalam permainan, saya hanya akan melakukan sinkronisasi waktu ini hanya sekali, klien akan memiliki perkiraan yang cukup baik mengenai waktu server dan kedua jam harus bergerak maju kira-kira pada kecepatan yang sama. Satu-satunya pengecualian adalah jika Anda menerima paket yang tampaknya berasal dari masa depan. Dalam hal ini, ada 2 solusi: 1) Lakukan sinkronisasi waktu baru. 2) Tingkatkan jam Anda agar sesuai dengan jam yang akan datang
John McDonald
Ok, mari kita lihat situasi ini hanya untuk memastikan saya mendapatkannya: Waktu server: 1s Waktu klien: 0s 150ms untuk sampai ke server Waktu server: 1.15s Waktu klien: 0.15s Server mengirimkan klien 1.15s 200ms untuk sampai ke klien Jadi, ping saya sekarang adalah 350 ms. Apakah itu benar? Waktu server: 1.35 Waktu klien: 0.35 Melakukan kalori: 1.15 - .35 + (0.35 - 0.00) / 2 Sekarang deltaTime saya = 0,975 Jika saya menambahkan waktu delta 0,975 ke 0,35 saya, saya mendapat: 1,325 Wich adalah jenis desync. Apakah itu benar juga?
gmemario
@ Griffson, Itu benar. Jika latensi untuk kedua paket berbeda (hampir dijamin), perhitungan waktu delta klien tidak akan sempurna. Tidak ada cara bagi klien untuk menjadi sempurna. Dalam algoritma yang Anda uraikan dalam pertanyaan, waktu delta dihitung beberapa kali dan ada metode untuk memilih dan rata-rata hasil ini. Banyak metode sinkronisasi waktu akan melakukan sesuatu seperti ini, tetapi mereka biasanya untuk server bisnis yang kritis dan jangka panjang seperti untuk pertukaran saham. Untuk ketepatan waktu yang Anda butuhkan untuk permainan pendek, saya pikir itu akan berlebihan.
John McDonald
@ Griffson, Selama klien memiliki estimasi waktu server yang masuk akal dan kedua jam bergerak maju dengan laju yang kira-kira sama, Anda seharusnya tidak melihat masalah apa pun. Ketika klien atau server mengirim tindakan ke sisi lain, mereka akan mengirimkan waktu lokal mereka. Di sisi penerima, pesan harus selalu di masa lalu dan perlu ditafsirkan sebagai peristiwa masa lalu. Ini berarti Anda memerlukan semua informasi dalam paket, seperti lokasi, kecepatan (besarnya + arah) dan waktu. Kemudian Anda dapat menempatkan keping di sana-sini, dan memindahkan keping dari masa lalu ke masa sekarang. Saya sedang mengobrol btw
John McDonald