Підтвердження надійності за допомогою UDP


16

У мене питання щодо UDP. Для контексту я працюю над екстреною грою в реальному часі.

Я читав зовсім небагато про відмінності між UDP та TCP і відчуваю, що я їх досить добре розумію, але є одна деталь, яка ніколи не вважала себе правильною, і це надійність , а саме визнання . Я розумію, що UDP не надає надійності за замовчуванням (тобто пакети можна скинути або вийти з ладу). Коли потрібна певна надійність, рішення, яке я бачив (що має сенс концептуально) полягає у використанні підтверджень (тобто сервер надсилає клієнту пакет, і коли клієнт отримує це повідомлення, він повертає підтвердження на сервер) .

Що відбувається, коли підтвердження відмінено?

У наведеному вище прикладі (один сервер, що надсилає пакет одному клієнту), сервер обробляє потенційну втрату пакету шляхом повторного надсилання пакетів кожен кадр, поки не будуть отримані підтвердження для цих пакетів. Ви все ще можете зіткнутися з проблемами пропускної здатності або повідомленнями, що не входять в порядок, але сервер охоплюється виключно з точки зору втрати пакетів.

Однак якщо клієнт надсилає підтвердження, яке ніколи не надходить, сервер не матиме нічого іншого, як врешті-решт припинити надсилати це повідомлення, яке може зламати гру, якщо потрібна інформація, що міститься в цьому пакеті. Ви можете скористатись аналогічним підходом до сервера (тобто продовжувати надсилати підтвердження, поки не отримаєте ак за ack?), Але такий підхід дозволить вам навіюватися назад і вперед назавжди (оскільки вам знадобиться ак за хек для ack і так далі).

Я вважаю, що моя основна логіка тут правильна, що залишає мені два варіанти.

  1. Надішліть єдиний пакет підтвердження і сподівайтеся на найкраще.
  2. Надішліть кілька пакунків із підтвердженнями (можливо, 3-4) та сподівайтеся на найкраще, припускаючи, що не всі вони будуть відкинуті.

Чи є відповідь на цю проблему? Я принципово щось не розумію? Чи є якась гарантія використання UDP, про яку я не знаю? Я не вагаюсь рухатись вперед із занадто великим кодом мереж, поки мені не зручно, що моя логіка є здоровою.


11
Можливо, вам не вистачає уявлення про "тайм-аути" та "повторні спроби".
Кромстер каже, що підтримую Моніку

Я, можливо, точно. Ви припускаєте, що моя логіка правильна і, як би це не звучало занадто негативно, але, хоч мережеве програмування, я не можу взяти на себе жодних гарантій практично на будь-якій частині мережевої інформації? Під час гри в режимі реального часу це кількість потенційно відкинутої інформації, це добре, але я просто хочу переконатися, що я розумію проблему.
Grimelios

10
Гарантій взагалі немає. Правильно. Ніколи не включайте "надію" у свої алгоритми. Вони повинні справляти будь-які нещасливі комбінації. PS Ми просто перейшли на TCP в нашому РТС, де піклується про eberything, оскільки нам потрібна надійна комунікація (для моделювання блокування кроків).
Кромстер каже, що підтримую Моніку

5
Використовуйте TCP, коли потрібна надійність, використовуйте UDP, коли це не має значення. Наприклад, координати гравця надсилаються в моїй грі через UDP. Я використовую інтерполяцію та згладжування, щоб згладити будь-які відсутні пакети. працює як шарм. речі, які дійсно повинні бути надійними, але можуть бути трохи повільнішими, надсилаються через TCP. Якщо у вас є стан, де новіший стан недійсний старого стану, UDP є хорошим вибором, оскільки це не має значення, коли щось середнє було скинуто 8е.г. позиція гравця).
Полігном

Це не пряма відповідь на ваше запитання, але я настійно рекомендую вимагати підтвердження лише в грі в реальному часі, коли вони абсолютно необхідні (наприклад, при початковому підключенні). Набагато простіше (і надійно) спроектувати і клієнта, і сервера, щоб вони «працювали з тим, що у них є», поки не зможуть отримати новий пакет в системі без стану, якщо можете. Quake 3 зробив це надзвичайно добре за допомогою системи на основі знімків . Також такі бібліотеки, як Enet, можуть надійно надсилати лише певні пакети для тих випадків, коли вам це справді потрібно
jrh

Відповіді:


32

Це форма Проблеми Двох Генералів , і Ви маєте рацію - жодної кількості повторних спроб недостатньо, щоб повністю гарантувати отримання.

На практиці в іграх зазвичай існує часовий горизонт, поза яким інформація насправді не має значення, навіть якщо технічно надходить надійно. Як і дізнатися, у вас був ідеальний вистріл у голову 2 секунди тому - гравцеві вже зараз використовувати цю інформацію.

Якщо ваші втрати пакету настільки великі, що ви не можете звичайно отримувати необхідну інформацію через щільне вікно реакції, то для гри в реальному часі вам може бути краще бити гравцем і намагатися знайти кращу відповідність для них в іншому місці, а не продовжуйте намагатися надіслати пакет, щоб імітувати надійне з'єднання.

Через це деякі системи реплікації гри взагалі пропускають підтвердження та повторення та вирішують просто спамувати найновіше оновлення якомога частіше. Якщо хтось потрапляє або приходить пізно, занадто погано, пропустіть його, підберіть наступний і продовжуйте, покладаючись на системи прогнозування та інтерполяції, щоб згладити розрив і мінімізувати ікони, видимі гравцеві.

Я раптом хочу почати називати цю "Реплікацію Сімба" за те, як вона нехтує проблемами в минулому і намагається жити в теперішньому моменті. ;)

Рафікі закладає певну редукцію на цю життєву філософію

Гібридним рішенням є гонка наперед, надсилаючи нове оновлення AND (оскільки оновлення стану гри часто можуть бути дуже маленькими / стисливими) ), також упаковка останнього оновлення, а може бути і попереднього оновлення ... Тож на всякий випадок, якщо клієнт пропустив їх , вам не доведеться чекати повний час подорожі, щоб дізнатися і виправити це. Більшу частину часу клієнт це вже бачив, тому таким чином є зайві дані, але затримка виправлення пропущеного повідомлення нижча. Оновлення клієнта можуть включати номер індексу останніх послідовних оновлень, які вони бачили, тому ви можете бути мінімально консервативними щодо того, скільки старих оновлень ви включаєте в наступний пакет оновлень.

Ви також можете реалізувати дворівневу систему як інший тип гібриду, коли короткочасний стан реплікується ненадійним швидким вогнем, а довгостроковий стан надійно синхронізується, використовуючи TCP або власну реалізацію надійності з високим спробою рахувати. Це стає складнішим в управлінні, оскільки у вас є дві системи обміну повідомленнями, і два знімки можуть не синхронізуватися між собою, додаючи цілий новий клас кращого випадку.


1
+1, добре написано. Я просто підкреслив би, що це більше стосується ігор чи дійсних ігор. Ігри TBS та RTS (а також деякі дії в грі) мають інший погляд на "часовий горизонт, поза яким інформація насправді не має значення".
Кромстер каже, що підтримую Моніку

3
Так, для покрокової гри я думаю, що можна використовувати TCP, а не намагатися прокрутити власний рівень надійності поверх UDP. ;) Я все-таки класифікую мікро в RTS як тип гри з захоплюючим часовим горизонтом - цей гібридний підхід може зробити добре там, де у вас є як оновлення з низькою затримкою для поточного моменту, так і мережа безпеки для зворотного вправляння критичних пропущених подій, таких як витрачання ресурсів.
DMGregory

Це надзвичайно корисно і своєрідно підтверджує мою первинну турботу. Велике спасибі.
Grimelios

2
Також може бути корисним згадати виправлення помилок вперед. Створіть свій протокол таким чином, щоб одержувач міг самостійно зрозуміти, що пакет був скинутий при отриманні наступного пакету, додавши додаткові дані, щоб згладити необхідну інтерполяцію. Це може бути корисно, оскільки часто пакети UDP все-таки не заповнені, і ви просто надсилаєте менші пакети частіше, щоб зменшити затримку. Додавання додаткових байтів не зашкодить затримки, а пропускна здатність не є проблемою у цих випадках.
MSalters

@MSalters Я б сказав, що це варто детальніше розглянути у власній відповіді, якщо ви готові до цього. Я б підтримав це. :)
DMGregory

9

Підхід, який використовує TCP, полягає в тому, що відправник буде продовжувати повторне надсилання пакета, поки не отримає підтвердження. Одержувач ігнорує повторювані пакети, але все ж надсилатиме підтвердження за них. Відправник проігнорує повторювані підтвердження.

Якщо пакет загубиться, відправник відправить його, як ви вже знаєте.
Якщо підтвердження втрачається, відправник надсилає оригінальний пакет, через що одержувач повторно підтверджує підтвердження.

Якщо підтвердження не отримано протягом певного часу (можливо, 60 секунд або 20 повторень), гравець вважається відключеним від гри. Ви повинні реалізувати якесь правило тайм-ауту, інакше гравець, який відключає мережевий кабель, назавжди зв’яже ресурси на вашому сервері.


Важливою особливістю TCP є те, що відправнику не потрібно дбати про те, чи визнано якийсь певний пакет, але в основному потрібно дбати про "високу водяну позначку" та про те, як довгі пакети були непогашеними без переміщення знака високої води.
supercat

1
@supercat Я б не сказав, що це важливо; більше схожа на оптимізацію.
користувач253751

Щодо речі в дужках (надсилання ACK для пакетів, які ви вже отримали), я думаю, вам слід насправді підкреслити це, а не дужки. Здається, це відсутнє в розумінні ОП (або принаймні його описі).
Ендже вже не пишається SO

@Angew зроблено зараз.
користувач253751

6

Якщо ви хочете заново створити TCP, то має сенс переглянути спочатку TCP , який стосується точної описаної вами проблеми (частина рішення полягає у використанні визначених користувачем значень для спроб повторних спроб та таймаутів).

Рішення, які використовують 2 канали, канал TCP (для надійного зв'язку), а також канал UDP (для зв'язку з низькою затримкою) - не рідкість.

Деякі рішення виявляють, коли клієнту не вистачає деякої інформації занадто довго, і починають ресинхронізацію, яка може використовувати UDP або TCP.

Ще один загальний підхід - це спроектувати комунікацію таким чином, щоб вона взагалі не покладалася на визнання, але це поза сферою питання.


3

У RTS ви дійсно не можете використовувати такий протокол, як TCP, і ви також не можете зробити UDP надійним. Якщо ви спробуєте це, гра замерзне, коли з'явиться мережеве підключення.

Натомість ви розробляєте протокол так, щоб пропущені пакети не мали великого значення.

Коротка версія полягає в тому, що вам байдуже, де інші гравці були останнім фреймом, поки ви знаєте, де вони зараз . Довга версія - більш складна.

Тоді виникає питання, що ви робите, коли пакет пропаде? А відповідь - ви здогадуєтесь. Гравець, ймовірно, рухається по прямій лінії, правда? Просто перемістіть їх на крок далі по цій лінії. ... За винятком жодного програвача RTS не рухається по прямій лінії. А далі відбувається виявлення зіткнення.

Це важко. Багато ігор помиляються. Можна стверджувати, що немає правильної відповіді, лише різні помилки, якими можна протистояти.

Причина, по якій ці ігри працюють досить добре, полягає не тільки в тому, що вони довго і наполегливо думали над цими проблемами, а й у тому, що Інтернет став досить надійним. Майже всі пакети UDP фактично своєчасно дістаються пункту призначення. (Якщо не існує постійної проблеми, як брандмауер)


Warcraft 3 використовує TCP.
fsp
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.