Keandalan pengakuan menggunakan UDP


16

Saya punya pertanyaan tentang UDP. Untuk konteks, saya sedang mengerjakan game aksi real-time.

Saya sudah membaca sedikit tentang perbedaan antara UDP dan TCP dan saya merasa saya memahaminya dengan baik, tetapi ada satu bagian yang tidak pernah terasa benar, dan itu keandalan , dan secara khusus ucapan terima kasih . Saya mengerti bahwa UDP tidak menawarkan keandalan secara default (yaitu paket dapat dibatalkan atau tiba tidak sesuai pesanan). Ketika beberapa keandalan diperlukan, solusi yang saya lihat (yang masuk akal secara konseptual) adalah dengan menggunakan ucapan terima kasih (yaitu server mengirim paket ke klien, dan ketika klien menerima pesan itu, ia mengirim kembali pengakuan ke server) .

Apa yang terjadi ketika pengakuan dijatuhkan?

Dalam contoh di atas (satu server mengirim paket ke satu klien), server menangani kemungkinan kehilangan paket dengan mengirim kembali paket setiap frame sampai ucapan terima kasih diterima untuk paket-paket itu. Anda masih bisa mengalami masalah bandwidth atau pesan out-of-order, tetapi murni dari perspektif packet-loss, server dicakup.

Namun, jika klien mengirim pemberitahuan yang tidak pernah tiba, server tidak akan punya pilihan selain berhenti mengirim pesan itu, yang dapat merusak permainan jika informasi yang terkandung dalam paket itu diperlukan. Anda dapat mengambil pendekatan yang mirip dengan server (yaitu terus mengirim ucapan terima kasih hingga Anda menerima ack untuk ack?), Tetapi pendekatan itu akan membuat Anda berulang kali bolak-balik (karena Anda memerlukan ack untuk ack untuk ack untuk ack? dan seterusnya).

Saya merasa logika dasar saya benar di sini, yang membuat saya memiliki dua opsi.

  1. Kirim paket pengakuan tunggal dan berharap yang terbaik.
  2. Kirim beberapa paket ucapan terima kasih (mungkin 3-4) dan berharap yang terbaik, dengan asumsi bahwa tidak semuanya akan dijatuhkan.

Apakah ada jawaban untuk masalah ini? Apakah saya salah paham secara mendasar tentang sesuatu? Apakah ada jaminan menggunakan UDP yang tidak saya sadari? Saya merasa ragu untuk bergerak maju dengan terlalu banyak kode jaringan sampai saya merasa nyaman karena logika saya sehat.


11
Mungkin Anda kehilangan gagasan "batas waktu" dan "coba lagi".
Kromster mengatakan mendukung Monica

Mungkin saya yakin. Anda menyarankan logika saya benar dan, tidak terdengar terlalu negatif, tetapi saat pemrograman jaringan, saya tidak dapat mengasumsikan hampir semua informasi jaringan? Selama permainan real-time, itu satu ton informasi yang berpotensi turun, yang baik-baik saja, tapi saya hanya ingin memastikan saya memahami masalah ini.
Grimelios

10
Tidak ada jaminan sama sekali. Baik. Jangan pernah memasukkan "harapan" dalam algoritme Anda. Mereka harus menangani kombinasi sial APAPUN. PS Kami hanya beralih ke TCP di RTS kami, di mana eberything diurus, karena kami membutuhkan komunikasi yang andal (untuk simulasi lockstep).
Kromster mengatakan mendukung Monica

5
Gunakan TCP saat keandalan diperlukan, gunakan UDP saat tidak penting. Misalnya, koordinat pemain dikirim dalam permainan saya melalui UDP. Saya menggunakan interpolasi & perataan untuk menghaluskan semua paket yang hilang. bekerja seperti pesona. hal-hal yang benar-benar harus dapat diandalkan tetapi dapat sedikit lebih lambat dikirim melalui TCP. Jika Anda memiliki negara tempat negara bagian yang lebih baru membatalkan negara bagian yang lama, UDP adalah pilihan yang baik karena tidak masalah ketika sesuatu di antaranya dibatalkan 8e.g. Posisi pemain).
Polygnome

Ini bukan jawaban langsung untuk pertanyaan Anda, tetapi saya sangat menyarankan hanya membutuhkan pengakuan dalam permainan waktu nyata ketika mereka benar-benar diperlukan (misalnya, pada koneksi awal). Jauh lebih sederhana (dan kokoh) untuk mendesain klien dan server sehingga mereka "bekerja dengan apa yang mereka miliki" sampai mereka mendapatkan paket baru dalam sistem tanpa kewarganegaraan jika Anda bisa. Gempa 3 melakukan ini dengan sangat baik dengan sistem berbasis snapshot . Juga perpustakaan seperti Enet hanya dapat mengirim paket tertentu dengan andal, untuk kasus-kasus ketika Anda benar-benar membutuhkannya
jrh

Jawaban:


32

Ini adalah bentuk Masalah Dua Jenderal , dan Anda benar - tidak ada jumlah percobaan yang cukup untuk menjamin penerimaan dengan sempurna.

Dalam latihan di gim, biasanya ada cakrawala waktu di mana informasi tidak terlalu penting walaupun itu secara teknis dapat diandalkan. Seperti mengetahui bahwa Anda memiliki headshot yang sempurna berbaris 2 detik yang lalu - sudah terlambat bagi pemain untuk menggunakan informasi itu sekarang.

Jika kehilangan paket Anda sangat tinggi sehingga Anda tidak dapat secara rutin mendapatkan info yang dibutuhkan melalui jendela reaksi ketat, maka untuk permainan waktu nyata Anda mungkin lebih baik menendang pemain dan mencoba menemukan kecocokan yang lebih baik untuk mereka di tempat lain, daripada terus mencoba mengirim paket untuk meniru koneksi yang andal.

Karena itu, beberapa sistem replikasi game melewatkan pengakuan & mencoba ulang sama sekali dan memilih hanya mengirim spam pembaruan terbaru sesering mungkin. Jika seseorang terjatuh atau datang terlambat, sayang sekali, lewati saja, ambil yang berikutnya dan lanjutkan, mengandalkan sistem prediksi & interpolasi untuk memperlancar jarak dan meminimalkan cegukan yang terlihat oleh pemain.

Saya tiba-tiba ingin mulai menyebut ini "Replikasi Simba" untuk bagaimana ia mengabaikan masalah di masa lalu dan mencoba untuk hidup di saat ini. ;)

Rafiki meletakkan beberapa reductio ad absurdum pada filosofi kehidupan itu

Solusi hibrida adalah berlomba untuk mengirimkan pembaruan baru DAN (karena pembaruan keadaan permainan sering kali sangat kecil / kompresibel) ) juga mengemas pembaruan terakhir, dan mungkin yang sebelum itu ... Jadi kalau-kalau klien melewatkannya , Anda tidak perlu menunggu waktu perjalanan penuh untuk mencari tahu dan memperbaikinya. Sebagian besar waktu klien sudah melihat ini, jadi ada data yang berlebihan dengan cara ini, tetapi latensi untuk memperbaiki pesan yang terlewatkan lebih rendah. Pembaruan klien dapat menyertakan nomor indeks dari pembaruan berturut-turut terbaru yang pernah mereka lihat, sehingga Anda dapat sedikit konservatif dengan berapa banyak pembaruan lama yang Anda sertakan dalam paket pembaruan berikutnya.

Anda juga dapat menerapkan sistem dua tingkat sebagai jenis hibrid lain, di mana keadaan berumur pendek direplikasi dengan cara cepat-api yang tidak dapat diandalkan, dan keadaan jangka panjang disinkronkan secara andal, menggunakan TCP atau implementasi keandalan Anda sendiri dengan coba lagi menghitung. Ini menjadi lebih rumit untuk dikelola, karena Anda memiliki dua sistem pengiriman pesan untuk dipelihara, dan kedua snapshot tersebut dapat tidak selaras satu sama lain, menambahkan kelas kasus tepi yang sama sekali baru.


1
+1, ditulis dengan baik. Saya hanya akan menyoroti, bahwa ini lebih relevan dengan game action / real-time. Game TBS dan RTS (dan beberapa acara game aksi) memiliki pandangan berbeda tentang "cakrawala waktu di mana informasi tidak terlalu penting".
Kromster mengatakan mendukung Monica

3
Ya, untuk permainan berbasis giliran, saya bayangkan seseorang akan menggunakan TCP daripada mencoba untuk menggulung lapisan keandalan sendiri di atas UDP. ;) Saya masih mengklasifikasikan mikro dalam RTS sebagai jenis gameplay dengan cakrawala waktu yang tepat - pendekatan hibrid mungkin berhasil di sana, di mana Anda memiliki pembaruan latensi rendah untuk panas saat ini maupun jaring pengaman untuk secara surut menangani peristiwa-peristiwa penting yang terlewat seperti pengeluaran sumber daya.
DMGregory

Itu sangat membantu dan memvalidasi masalah awal saya. Terima kasih banyak.
Grimelios

2
Mungkin juga bermanfaat untuk menyebutkan Koreksi Kesalahan Maju. Rancang protokol Anda sehingga penerima dapat mengetahui secara independen bahwa suatu paket dijatuhkan ketika paket berikutnya diterima, menambahkan beberapa data tambahan untuk memperlancar interpolasi yang diperlukan. Ini bisa bermanfaat karena seringkali paket UDP tidak penuh, dan Anda hanya mengirim paket kecil lebih sering untuk menjaga latensi tetap rendah. Menambahkan beberapa byte tambahan tidak akan mengganggu latensi, dan bandwidth tidak menjadi masalah dalam kasus ini.
MSalters

@ MSalters Saya akan mengatakan itu layak diuraikan dalam jawabannya sendiri, jika Anda siap untuk itu. Saya akan mengatakan itu. :)
DMGregory

9

Pendekatan yang digunakan TCP adalah pengirim akan terus mengirim ulang paket sampai menerima pemberitahuan. Penerima akan mengabaikan paket duplikat, tetapi masih mengirimkan ucapan terima kasih kepada mereka. Pengirim akan mengabaikan duplikat ucapan terima kasih.

Jika suatu paket hilang, pengirim mengirimnya kembali, seperti yang sudah Anda ketahui.
Jika pemberitahuan hilang, pengirim mengirim ulang paket aslinya, yang menyebabkan penerima mengirim ulang pemberitahuan.

Jika pengakuan tidak diterima dalam waktu tertentu (mungkin 60 detik, atau 20 coba lagi) maka pemain dianggap terputus dari permainan. Anda harus menerapkan semacam aturan batas waktu, atau jika pemain yang mencabut kabel jaringannya akan mengikat sumber daya di server Anda selamanya.


Fitur penting dari TCP adalah bahwa pengirim tidak perlu peduli apakah ada paket tertentu yang diakui, tetapi sebagian besar perlu peduli tentang "tanda air tinggi" dan berapa lama paket telah beredar tanpa tanda air tinggi bergerak.
supercat

1
@ supercat Saya tidak akan mengatakan itu penting; lebih seperti sebuah optimasi.
user253751

Mengenai hal dalam tanda kurung (mengirim ACK untuk paket yang sudah Anda dapatkan), saya pikir Anda harus benar-benar menekankannya daripada tanda kurung. Tampaknya hilang dari pemahaman OP (atau setidaknya deskripsinya).
Angew tidak lagi bangga dengan SO

@ Baru selesai sekarang.
user253751

6

Jika Anda ingin menemukan kembali TCP, masuk akal untuk melihat TCP terlebih dahulu, yang berkaitan dengan masalah yang Anda jelaskan (bagian dari solusi adalah menggunakan nilai yang ditentukan pengguna untuk mencoba ulang dan waktu habis).

Solusi yang menggunakan 2 saluran, saluran TCP (untuk komunikasi yang andal) serta saluran UDP (untuk komunikasi latensi rendah) tidak jarang.

Beberapa solusi mendeteksi ketika klien melewatkan beberapa informasi terlalu lama, dan memulai sinkronisasi ulang, yang mungkin menggunakan UDP atau TCP.

Pendekatan umum lainnya adalah merancang komunikasi sedemikian rupa sehingga tidak mengandalkan pengakuan sama sekali, tetapi itu di luar ruang lingkup pertanyaan.


3

Dalam RTS Anda benar-benar tidak dapat menggunakan protokol seperti TCP, dan Anda juga tidak bisa membuat UDP dapat diandalkan. Jika Anda mencoba, permainan akan membeku setiap kali ada hick-up jaringan.

Sebagai gantinya, Anda mendesain protokol sehingga paket yang terlewatkan tidak terlalu penting.

Versi singkatnya adalah Anda tidak peduli di mana para pemain lainnya berada di frame terakhir selama Anda tahu di mana mereka sekarang . Versi panjang lebih rumit.

Pertanyaannya kemudian, apa yang Anda lakukan ketika sebuah paket hilang? Dan jawabannya adalah ... Anda menebak. Pemain mungkin bergerak dalam garis lurus, bukan? Pindahkan mereka satu langkah lebih jauh di sepanjang garis itu. ... Kecuali tidak ada pemain RTS yang pernah bergerak dalam garis lurus. Dan kemudian ada deteksi tabrakan.

Ini sulit. Banyak game yang salah. Dapat dikatakan bahwa tidak ada jawaban yang tepat untuk ini, hanya berbagai kesalahan yang dapat ditukar.

Alasan mengapa game-game ini bekerja dengan baik bukan hanya karena mereka telah berpikir panjang dan keras tentang masalah-masalah ini, tetapi juga bahwa Internet telah menjadi sangat andal. Hampir semua paket UDP benar-benar mencapai tujuan mereka tepat waktu. (Kecuali jika ada masalah permanen seperti firewall)


Warcraft 3 menggunakan TCP.
fsp
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.