Mam pytanie dotyczące UDP. Dla kontekstu pracuję nad grą akcji w czasie rzeczywistym.
Przeczytałem sporo o różnicach między UDP i TCP i wydaje mi się, że rozumiem je całkiem dobrze, ale jest jedna rzecz, która nigdy nie wydawała się poprawna, a jest to niezawodność , a zwłaszcza podziękowania . Rozumiem, że UDP domyślnie nie zapewnia niezawodności (tzn. Pakiety mogą być odrzucane lub wysyłane poza kolejnością). Gdy wymagana jest pewna niezawodność, rozwiązaniem, które widziałem (co ma sens z koncepcyjnego punktu widzenia) jest użycie potwierdzeń (tj. Serwer wysyła pakiet do klienta, a kiedy klient odbiera tę wiadomość, odsyła potwierdzenie do serwera) .
Co dzieje się po odrzuceniu potwierdzenia?
W powyższym przykładzie (jeden serwer wysyła pakiet do jednego klienta) serwer radzi sobie z potencjalną utratą pakietów poprzez ponowne wysyłanie pakietów co ramkę, dopóki nie zostaną odebrane potwierdzenia dla tych pakietów. Nadal możesz napotykać problemy z przepustowością lub komunikatami o nieporządku, ale wyłącznie z punktu widzenia utraty pakietów serwer jest objęty.
Jeśli jednak klient wyśle potwierdzenie, które nigdy nie dotrze, serwer nie będzie miał innego wyjścia, jak ostatecznie przestać wysyłać tę wiadomość, co może przerwać grę, jeśli informacje zawarte w tym pakiecie będą wymagane. Możesz zastosować podobne podejście do serwera (tj. Wysyłać potwierdzenia aż do otrzymania potwierdzenia dla potwierdzenia?), Ale takie podejście spowodowałoby, że będziesz zapętlał się w tę iz powrotem na zawsze (ponieważ będziesz potrzebował potwierdzenia dla potwierdzenia dla potwierdzenia i tak dalej).
Czuję, że moja podstawowa logika jest tutaj poprawna, co pozostawia mi dwie opcje.
- Wyślij pojedynczy pakiet potwierdzenia i miej nadzieję na najlepsze.
- Wyślij garść pakietów potwierdzających (może 3-4) i licz na najlepsze, zakładając, że nie wszystkie zostaną odrzucone.
Czy istnieje odpowiedź na ten problem? Czy zasadniczo coś nie rozumiem? Czy jest jakaś gwarancja używania UDP, o której nie wiem? Waham się, czy iść naprzód z nadmiarem kodu sieciowego, dopóki nie poczuję się dobrze, że moja logika jest dobra.
źródło
Odpowiedzi:
Jest to forma problemu dwóch generałów i masz rację - nie ma wystarczającej liczby ponownych prób, aby idealnie zagwarantować odbiór.
W praktyce w grach zwykle istnieje horyzont czasowy, poza którym informacje tak naprawdę nie mają znaczenia, nawet jeśli technicznie docierają one niezawodnie. Podobnie jak w przypadku stwierdzenia, że masz 2 sekundy temu idealny strzał w głowę w szeregu - jest już za późno, aby gracz mógł teraz użyć tych informacji.
Jeśli Twoja utrata pakietów jest tak duża, że nie możesz rutynowo uzyskać potrzebnych informacji przez ciasne okno reakcji, to w przypadku gry w czasie rzeczywistym lepiej byłoby kopnąć gracza i spróbować znaleźć dla nich lepsze dopasowanie w innym miejscu niż kontynuuj próby wysłania pakietu w celu emulacji niezawodnego połączenia.
Z tego powodu niektóre systemy replikacji gier całkowicie pomijają potwierdzanie i ponawianie prób i wybierają spamowanie najnowszej aktualizacji tak często, jak to możliwe. Jeśli ktoś zostanie upuszczony lub spóźni się, szkoda, pomiń go, podnieś następny i kontynuuj, korzystając z systemów przewidywania i interpolacji, aby wygładzić lukę i zminimalizować czkawkę widoczną dla gracza.
Nagle chcę zacząć nazywać to „replikacją Simba”, ponieważ ignoruje problemy z przeszłości i próbuje żyć w chwili obecnej. ;)
Rozwiązaniem hybrydowym jest ściganie się z wyprzedzeniem, wysyłając nową aktualizację ORAZ (ponieważ aktualizacje stanu gry często mogą być dość małe / nadające się do kompresji ) również spakować ostatnią aktualizację, a może poprzednią ... Więc na wypadek gdyby klient przegapił , nie musisz czekać pełnego czasu podróży w obie strony, aby się dowiedzieć i naprawić. Przez większość czasu klient już to widział, więc w ten sposób są nadmiarowe dane, ale opóźnienie korekty pominiętej wiadomości jest niższe. Aktualizacje klienta mogą zawierać numer indeksu najnowszej kolejnej aktualizacji, którą widzieli, dzięki czemu możesz być minimalnie konserwatywny, ile starych aktualizacji umieścisz w następnym pakiecie aktualizacji.
Można również zaimplementować dwupoziomowy system jako inny rodzaj hybrydy, w którym stan krótkotrwały jest replikowany w niewiarygodny sposób szybkiego strzelania, a stan długoterminowy jest synchronizowany niezawodnie, przy użyciu protokołu TCP lub własnej implementacji niezawodności o wysokiej próbie liczyć. Jest to jednak bardziej skomplikowane w zarządzaniu, ponieważ masz dwa systemy przesyłania wiadomości do utrzymania, a dwie migawki mogą nie być zsynchronizowane ze sobą, dodając zupełnie nową klasę wielkości liter.
źródło
Metoda TCP polega na tym, że nadawca będzie wysyłał pakiet ponownie, dopóki nie otrzyma potwierdzenia. Odbiornik zignoruje zduplikowane pakiety, ale nadal wyśle dla nich potwierdzenia. Nadawca zignoruje duplikaty potwierdzeń.
Jeśli pakiet zostanie zgubiony, nadawca wysyła go ponownie, jak już wiesz.
Jeśli potwierdzenie zostanie utracone, nadawca ponownie wysyła oryginalny pakiet, co powoduje, że odbiorca ponownie wysyła potwierdzenie.
Jeśli potwierdzenie nie zostanie odebrane w określonym czasie (być może 60 sekund lub 20 ponownych prób), gracz uważa się za odłączony od gry. Państwo musi wdrożyć jakieś reguły limitu czasu lub inny gracz, który odłączy ich kabel sieciowy będzie związać się zasobów na serwerze zawsze.
źródło
Jeśli chcesz wynaleźć TCP na nowo, warto spojrzeć na TCP najpierw , który dotyczy dokładnie opisanego problemu (część rozwiązania polega na użyciu wartości zdefiniowanych przez użytkownika do prób ponownych prób i przekroczeń limitu czasu).
Rozwiązania wykorzystujące 2 kanały, kanał TCP (do niezawodnej komunikacji) oraz kanał UDP (do komunikacji o niskim opóźnieniu) nie są rzadkie.
Niektóre rozwiązania wykrywają, gdy klient zbyt długo brakuje informacji, i rozpoczynają resynchronizację, która może wykorzystywać UDP lub TCP.
Innym powszechnym podejściem jest takie zaprojektowanie komunikacji, aby w ogóle nie opierała się na potwierdzeniach, ale to nie wchodzi w zakres pytania.
źródło
W RTS tak naprawdę nie można używać protokołu takiego jak TCP i nie można też uczynić UDP niezawodnym. Jeśli spróbujesz, gra zawiesi się za każdym razem, gdy nastąpi podłączenie do sieci.
Zamiast tego projektujesz protokół tak, aby pominięte pakiety nie miały większego znaczenia.
Krótka wersja jest taka, że nie obchodzi Cię, gdzie inni gracze byli w ostatniej klatce, o ile wiesz, gdzie są teraz . Długa wersja jest bardziej skomplikowana.
Powstaje zatem pytanie: co robisz, gdy brakuje pakietu? A odpowiedź brzmi ... tak myślicie. Gracz prawdopodobnie porusza się w linii prostej, prawda? Po prostu przesuń je o krok dalej wzdłuż tej linii. ... Tyle że żaden gracz RTS nigdy nie porusza się po linii prostej. A potem jest wykrywanie kolizji.
To jest trudne. Wiele gier źle to rozumie. Można argumentować, że nie ma na to właściwej odpowiedzi, tylko różne zło, które można wymienić.
Powodem, dla którego te gry działają całkiem nieźle, jest nie tylko to, że długo i intensywnie zastanawiali się nad tymi problemami, ale także, że Internet stał się dość niezawodny. Prawie wszystkie pakiety UDP faktycznie docierają na miejsce w odpowiednim czasie. (Chyba że istnieje stały problem, taki jak zapora ogniowa)
źródło