2009-09-23 13 views
13

Tworzę własne niestandardowe oprogramowanie serwera do gry w Javie (gra i oryginalne oprogramowanie serwera zostały napisane w Javie). Nie ma dostępnej dokumentacji protokołów, więc muszę czytać pakiety za pomocą Wiresharka.Co to jest aktualizacja okna TCP?

Podczas gdy klient łączy się z serwerem, wysyła plik poziomu w formacie Gzip. Przy około 94 pakietach wysyłania poziomu mój serwer powoduje awarię klienta z wyjątkiem ArrayIndexOutOfBoundsException. Zgodnie z plikiem przechwytywania z oryginalnego serwera, przesyła aktualizację okna TCP w przybliżeniu w tym punkcie. Co to jest aktualizacja okna TCP i jak wysłać ją przy użyciu SocketChannel?

Odpowiedz

50

Okna TCP służą do sterowania przepływem między urządzeniami równorzędnymi w połączeniu. Przy każdym pakiecie ACK host wysyła pole "rozmiar okna". W tym polu podano liczbę bajtów danych, które host może otrzymać, zanim będzie pełny. Nadawca nie powinien wysyłać więcej niż ta ilość danych.

Okno może się zapełnić, jeśli klient nie otrzymuje wystarczająco szybko danych. Innymi słowy, bufory TCP mogą się zapełniać, gdy aplikacja jest wyłączona, robiąc coś innego niż odczyt z gniazda. Gdy tak się stanie, klient wyśle ​​pakiet ACK z ustawionym bitem "pełnego okna". W tym momencie serwer powinien przestać wysyłać dane. Wszelkie pakiety wysłane do komputera z pełnym oknem będą uznawane za , a nie. (To spowoduje, że źle zachowany nadawca będzie retransmitował. Dobrze zachowany nadawca będzie po prostu buforował wychodzące dane .Jeśli bufor po stronie wysyłającej również się zapełni, to aplikacja wysyłająca zablokuje, gdy spróbuje zapisać więcej danych do gniazda !)

To jest stoisko TCP. Może się tak zdarzyć z wielu powodów, ale ostatecznie oznacza to, że nadawca przesyła szybciej niż czyta odbiornik.

Gdy aplikacja na końcu odbierającym wróci do odczytu z gniazda, spowoduje to odessanie niektórych buforowanych danych, co zwalnia trochę miejsca.Odbiorca wyśle ​​pakiet "aktualizacji okna", aby poinformować nadawcę, ile danych może przesłać. Nadawca rozpoczyna przesyłanie swoich zbuforowanych danych, a ruch powinien odbywać się normalnie.

Oczywiście można uzyskać powtarzające się przeciągnięcia, jeśli odbiornik jest konsekwentnie wolny.

Sformułowałem to tak, jakby nadawca i odbiorca byli inni, ale w rzeczywistości, obydwa węzły wymieniają aktualizacje okien z każdym pakietem ACK, a każda ze stron może zapełnić swoje okno.

Ogólna wiadomość jest taka, że ​​nie trzeba bezpośrednio wysyłać pakietów aktualizacji okien. Byłoby złym pomysłem, aby je podrobić.

Jeśli chodzi o wyjątek, który widzisz ... prawdopodobnie pakiet SVP nie będzie powodował ani mu zapobiegnie. Jeśli jednak klient nie czyta wystarczająco szybko, możesz utracić dane. Na swoim serwerze powinieneś sprawdzić wartość zwracaną przez połączenia Socket.write(). Może być mniejsza niż liczba bajtów, które próbujesz napisać. Dzieje się tak, gdy bufor nadawczy zostanie zapełniony, co może się zdarzyć podczas przeciągnięcia TCP. Możliwe, że tracisz bajty.

Na przykład, jeśli próbujesz napisać 8192 bajtów przy każdym wywołaniu zapisu, ale jedna z wywołań zwraca 5691, musisz wysłać pozostałe 2501 bajtów przy następnym połączeniu. W przeciwnym razie klient nie zobaczy pozostałej części tego bloku 8K, a twój plik będzie krótszy po stronie klienta niż po stronie serwera.

+3

Mój bug-fu mówi mi, że ten ostatni akapit prawdopodobnie przytył problem. – caf

+1

Świetne wyjaśnienie, dzięki! Dokładnie to, czego potrzebowałem. Myślę, że znalazłem przyczynę wyjątku - klient oczekiwał danych w innej, nieco dłuższej formie niż to, co wysyłałem. – phpscriptcoder

+0

+1, aby uzyskać szczegółowe wyjaśnienie! – Izza

7

Dzieje się to naprawdę głęboko w stosie TCP/IP; w aplikacji (serwerze i kliencie) nie musisz martwić się o okna TCP. Błąd musi być czymś innym.

2

Aktualizacja okna TCP ma związek z komunikacją dostępnego rozmiaru bufora między nadawcą a odbiorcą. Wyjątek ArrayIndexOutOfBoundsException nie jest prawdopodobną przyczyną. Najprawdopodobniej kod oczekuje pewnych danych, których nie otrzymuje (prawdopodobnie jeszcze przed tym punktem, do którego odnosi się dopiero teraz). Bez zobaczenia kodu i śladu stosu, naprawdę trudno powiedzieć coś więcej.

+0

Dzięki za pomoc. Śledzenie stosu nie jest zbyt pomocne, ponieważ kod klienta jest zaciemniany, więc wszystkie klasy i metody są pojedynczymi literami ... Potrzebne są dalsze badania! – phpscriptcoder

+0

@phpscriptcoder: Może powinieneś dostać oryginalnego programistę (ów) zwolniony ... –

0

Czy otrzymujesz details z exception?

Nie jest prawdopodobne, związane z pakietem TCP okno Aktualizacja
(widziałeś to powtórzyć dokładnie do wielu wystąpień?)

Bardziej prawdopodobne związane z kodem, który działa na przetwarzanie odebranych danych.

0

Zwykle jest to tylko wyzwalacz, a nie przyczyna problemu.

Na przykład, jeśli używasz selektora NIO, aktualizacja okna może uruchomić przebudzenie kanału zapisu. To z kolei powoduje błędną logikę w twoim kodzie.

Zdobądź stacktrace, a pokaże ci on główną przyczynę.

2

TCP WindowUpdate - wskazuje, że segment był czystym segmentem WindowUpdate. A WindowUpdate pojawia się, gdy aplikacja po stronie odbiorczej zużyła już odebrane dane z bufora RX, powodując, że warstwa TCP wysyła komunikat WindowUpdate na drugą stronę, aby wskazać, że w buforze jest teraz więcej miejsca. Zazwyczaj widziane po wystąpieniu warunku TCP ZeroWindow. Gdy aplikacja na odbiorniku pobierze dane z bufora TCP, zwalniając w ten sposób miejsce, odbiornik powinien powiadomić nadawcę, że warunek TCP ZeroWindow już nie istnieje, wysyłając komunikat TCP WindowUpdate, który reklamuje bieżący rozmiar okna.

https://wiki.wireshark.org/TCP_Analyze_Sequence_Numbers