Programowanie sieciowe - TCP. Aplikacja klient-serwer na gnieździe strumieniowym TCP Aplikacja Tcp Serwer klienta ip

Aplikacja klient-serwer na gnieździe strumieniowym TCP

W poniższym przykładzie zastosowano protokół TCP w celu zapewnienia uporządkowanych, niezawodnych dwukierunkowych strumieni bajtów. Zbudujmy kompletną aplikację zawierającą klienta i serwer. Najpierw pokazujemy, jak zbudować serwer przy użyciu gniazd strumieniowych TCP, a następnie aplikację kliencką do testowania naszego serwera.

Poniższy program tworzy serwer, który odbiera żądania połączeń od klientów. Serwer jest zbudowany synchronicznie, dlatego wykonywanie wątków jest blokowane do czasu, aż serwer zgodzi się na połączenie z klientem. Ta aplikacja demonstruje prosty serwer odpowiadający klientowi. Klient kończy połączenie wysyłając wiadomość do serwera .

Serwer TCP

Tworzenie struktury serwerowej obrazuje poniższy schemat funkcjonalny:

Oto pełny kod programu SocketServer.cs:

// SocketServer.cs przy użyciu Systemu; przy użyciu System.Text; przy użyciu System.Net; przy użyciu System.Net.Sockets; namespace SocketServer ( class Program ( static void Main(string args) ( // Ustaw lokalny punkt końcowy dla gniazda IPHostEntry ipHost = Dns.GetHostEntry("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = nowy IPEndPoint(ipAddr, 11000 ); // Utwórz gniazdo Tcp/Ip Socket sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Przypisz gniazdo do lokalnego punktu końcowego i spróbuj nasłuchiwać gniazd przychodzących ( sListener.Bind( ipEndPoint); sListener.Listen(10); // Rozpocznij nasłuchiwanie połączeń póki (true) ( ​​​​Console.WriteLine("Oczekiwanie na połączenie na porcie (0)", ipEndPoint); // Program zatrzymuje się w oczekiwaniu na połączenie przychodzące Socket handler = sListener.Accept(); string data = null; // Czekaliśmy, aż klient spróbuje się z nami połączyć byte bytes = nowy bajt; int bytesRec = handler.Receive(bytes); data += Kodowanie. UTF8.GetString(bytes, 0, bytesRec); // Pokaż dane w konsoli Console.Write("Otrzymany tekst: " + dane + "\n\n"); // Wyślij odpowiedź do klienta\ string odpowiedź = "Dziękujemy za żądanie w " + data.Length.ToString() + "znaki"; bajt msg = Encoding.UTF8.GetBytes(odpowiedź); handler.Wyślij(msg); if (dane.IndexOf(" ") > -1) ( Console.WriteLine("Serwer zakończył połączenie z klientem."); break; ) handler.Shutdown(SocketShutdown.Both); handler.Close(); ) ) catch (Wyjątek np.) ( Console.WriteLine (ex.ToString()); ) w końcu ( Console.ReadLine(); ) ) ) )

Przyjrzyjmy się strukturze tego programu.

Pierwszym krokiem jest ustawienie gniazda na lokalny punkt końcowy. Przed otwarciem gniazda w celu nasłuchiwania połączeń należy przygotować dla niego adres lokalnego punktu końcowego. Unikalny adres obsługi TCP/IP jest określany przez kombinację adresu IP hosta z numerem portu obsługi, co tworzy obsługujący punkt końcowy.

Klasa Dns udostępnia metody zwracające informacje o adresach sieciowych obsługiwanych przez urządzenie w sieci lokalnej. Jeśli urządzenie LAN ma więcej niż jeden adres sieciowy, klasa Dns zwraca informacje o wszystkich adresach sieciowych, a aplikacja musi wybrać z tablicy odpowiedni adres do obsługi.

Utwórzmy IPEndPoint dla serwera łącząc pierwszy adres IP komputera hosta uzyskany metodą Dns.Resolve() z numerem portu:

IPHostEntry ipHost = Dns.GetHostEntry("localhost"); Adres IP ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = nowy IPEndPoint(ipAddr, 11000);

Tutaj klasa IPEndPoint reprezentuje localhost na porcie 11000. Następnie tworzymy gniazdo strumieniowe z nową instancją klasy Socket. Po skonfigurowaniu lokalnego punktu końcowego do nasłuchiwania połączeń możemy utworzyć gniazdo:

Socket sListener = nowe gniazdo (ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

Przenosić AdresRodzina określa schematy adresowania, których instancja klasy Socket może użyć do rozpoznania adresu.

W parametrze Typ gniazda Gniazda TCP i UDP są różne. Można w nim zdefiniować między innymi następujące wartości:

Wykres

Obsługuje datagramy. Wartość Dgram wymaga określenia Udp dla typu protokołu i InterNetwork w parametrze rodziny adresów.

Surowy

Obsługuje dostęp do podstawowego protokołu transportowego.

Strumień

Obsługuje gniazda strumieniowe. Wartość Stream wymaga określenia Tcp dla typu protokołu.

Trzeci i ostatni parametr określa typ protokołu wymagany dla gniazda. W parametrze Typ protokołu Możesz określić następujące najważniejsze wartości - Tcp, Udp, Ip, Raw.

Kolejnym krokiem powinno być przypisanie gniazda metodą Wiązać(). Kiedy gniazdo jest otwierane przez konstruktora, nie jest mu przypisana nazwa, zarezerwowany jest jedynie uchwyt. Metoda Bind() jest wywoływana w celu przypisania nazwy gnieździe serwera. Aby gniazdo klienta mogło zidentyfikować gniazdo strumienia TCP, program serwera musi nadać swojemu gniazdu nazwę:

SListener.Bind(ipEndPoint);

Metoda Bind() wiąże gniazdo z lokalnym punktem końcowym. Metodę Bind() należy wywołać przed jakąkolwiek próbą wywołania metod Listen() i Accept().

Teraz, po utworzeniu gniazda i przypisaniu mu nazwy, możesz odsłuchiwać przychodzące wiadomości za pomocą tej metody Słuchać(). W stanie nasłuchiwania gniazdo będzie nasłuchiwać przychodzących prób połączenia:

SListener.Słuchaj(10);

Parametr określa zaległości, wskazujący maksymalną liczbę połączeń oczekujących w kolejce. W powyższym kodzie wartość parametru pozwala na zgromadzenie w kolejce do dziesięciu połączeń.

W stanie nasłuchiwania musisz być gotowy na wyrażenie zgody na połączenie z klientem, dla którego stosowana jest dana metoda Zaakceptować(). Ta metoda pozwala uzyskać połączenie klienta i zakończyć skojarzenie nazwy klienta i serwera. Metoda Accept() blokuje wątek programu wywołującego do czasu nadejścia połączenia.

Metoda Accept() usuwa pierwsze żądanie połączenia z kolejki żądań oczekujących i tworzy nowe gniazdo w celu jego przetworzenia. Chociaż tworzone jest nowe gniazdo, oryginalne gniazdo nadal nasłuchuje i może być używane w przypadku wielowątkowości w celu akceptowania wielu żądań połączeń od klientów. Żadna aplikacja serwerowa nie powinna zamykać gniazda nasłuchującego. Musi nadal współpracować z gniazdami utworzonymi przez metodę Accept w celu przetwarzania przychodzących żądań klientów.

While (true) ( ​​​​Console.WriteLine("Oczekiwanie na połączenie na porcie (0)", ipEndPoint); // Program zatrzymuje się w oczekiwaniu na połączenie przychodzące. Socket handler = sListener.Accept();

Gdy klient i serwer nawiążą ze sobą połączenie, wiadomości można wysyłać i odbierać za pomocą tych metod Wysłać() I Odbierać() Gniazdo klasy.

Metoda Send() zapisuje dane wychodzące do podłączonego gniazda. Metoda Otrzymaj() odczytuje przychodzące dane do gniazda strumieniowego. W przypadku korzystania z systemu opartego na protokole TCP przed wykonaniem metod Send() i otrzymać() należy nawiązać połączenie między gniazdami. Dokładny protokół pomiędzy dwoma komunikującymi się podmiotami musi zostać wcześniej zdefiniowany, aby aplikacje klienckie i serwerowe nie blokowały się wzajemnie, nie wiedząc, kto powinien wysłać swoje dane jako pierwszy.

Po zakończeniu wymiany danych pomiędzy serwerem a klientem należy zamknąć połączenie za pomocą metod Zamknięcie() I Zamknąć():

Handler.Shutdown(SocketShutdown.Both); handler.Close();

SocketShutdown to wyliczenie zawierające trzy wartości do zatrzymania: Obydwa- przestaje wysyłać i odbierać dane przez gniazdo, Odbierać- zatrzymuje gniazdo od odbierania danych i Wysłać- przestaje wysyłać dane przez gniazdo.

Gniazdo jest zamykane poprzez wywołanie metody Close(), która również ustawia właściwość Connected gniazda na wartość false.

Klient TCP

Funkcje, które służą do tworzenia aplikacji klienckiej, są mniej więcej podobne do aplikacji serwerowej. Podobnie jak w przypadku serwera, te same metody służą do określenia punktu końcowego, utworzenia instancji gniazda, wysyłania i odbierania danych oraz zamykania gniazda.

Serwery implementujące te protokoły w sieci korporacyjnej zapewniają klientowi adres IP, bramę, maskę sieci, serwery nazw, a nawet drukarkę. Użytkownicy nie muszą ręcznie konfigurować swoich hostów, aby korzystać z sieci.

System operacyjny QNX Neutrino implementuje inny protokół automatycznej konfiguracji o nazwie AutoIP, który jest projektem Komitetu Autokonfiguracji IETF. Protokół ten jest używany w małych sieciach do przypisywania hostom lokalnych adresów IP. Protokół AutoIP niezależnie określa adres IP lokalny dla łącza, korzystając ze schematu negocjacji z innymi hostami i bez konieczności kontaktowania się z serwerem centralnym.

Korzystanie z protokołu PPPoE

Skrót PPPoE oznacza protokół Point-to-Point przez Ethernet. Protokół ten hermetyzuje dane do transmisji w sieci Ethernet o topologii mostkowej.

PPPoE to specyfikacja umożliwiająca łączenie użytkowników sieci Ethernet z Internetem za pośrednictwem połączenia szerokopasmowego, takiego jak dzierżawiona cyfrowa linia abonencka, urządzenie bezprzewodowe lub modem kablowy. Zastosowanie protokołu PPPoE oraz modemu szerokopasmowego zapewnia użytkownikom lokalnej sieci komputerowej indywidualny, uwierzytelniony dostęp do szybkich sieci danych.

Protokół PPPoE łączy technologię Ethernet z protokołem PPP, skutecznie tworząc oddzielne połączenie ze zdalnym serwerem dla każdego użytkownika. Kontrola dostępu, rozliczanie połączeń i wybór dostawcy usług są ustalane dla użytkowników, a nie hostów. Zaletą tego podejścia jest to, że ani operator telefoniczny, ani dostawca usług internetowych nie muszą zapewniać w tym zakresie specjalnego wsparcia.

W przeciwieństwie do połączeń telefonicznych, połączenia DSL i modem kablowy są zawsze aktywne. Ponieważ fizyczne połączenie ze zdalnym dostawcą usług jest współdzielone przez wielu użytkowników, potrzebna jest metoda rozliczania, która rejestruje nadawców i miejsca docelowe ruchu oraz pobiera opłaty od użytkowników. Protokół PPPoE umożliwia użytkownikowi i zdalnemu hostowi uczestniczącemu w sesji komunikacyjnej wzajemne poznanie adresów sieciowych podczas początkowej wymiany zwanej wykrycie(odkrycie). Po ustanowieniu sesji pomiędzy indywidualnym użytkownikiem a zdalnym hostem (np. dostawcą usług internetowych) sesję można monitorować w celach naliczania. Wiele domów, hoteli i korporacji zapewnia publiczny dostęp do Internetu za pośrednictwem cyfrowych linii abonenckich wykorzystujących technologię Ethernet i protokół PPPoE.

Połączenie poprzez protokół PPPoE składa się z klienta i serwera. Klient i serwer działają przy użyciu dowolnego interfejsu zbliżonego do specyfikacji Ethernet. Interfejs ten służy do przydzielania adresów IP klientom i kojarzenia tych adresów IP z użytkownikami i, opcjonalnie, stacjami roboczymi, a nie samym uwierzytelnianiem na podstawie stacji roboczej. Serwer PPPoE tworzy połączenie punkt-punkt dla każdego klienta.

Konfigurowanie sesji PPPoE

Aby utworzyć sesję PPPoE należy skorzystać z usługipppoed. Modułio-pkt-*nZapewnia usługi protokołu PPPoE. Najpierw musisz biecio-pkt-*Zodpowiedni sterownik. Przykład:

TCP integruje się w naturalny sposób ze środowiskiem klient/serwer (patrz rysunek 10.1). Aplikacja serwerowa błędy(słuchaj) przychodzących żądań połączenia. Na przykład usługi WWW, przesyłania plików lub dostępu do terminali nasłuchują żądań przychodzących od klientów. Komunikację w protokole TCP inicjują odpowiednie procedury, które inicjują połączenie z serwerem (patrz rozdział 21 o interfejsie programowania gniazd).

Ryż. 10.1. Klient dzwoni do serwera.

W rzeczywistości klientem może być inny serwer. Na przykład serwery poczty mogą łączyć się z innymi serwerami poczty w celu wysyłania wiadomości e-mail między komputerami.

10.2 Pojęcia dotyczące protokołu TCP

W jakiej formie aplikacje powinny wysyłać dane w protokole TCP? W jakiej formie protokół TCP przesyła dane do protokołu IP? W jaki sposób protokoły wysyłające i odbierające TCP identyfikują połączenie między aplikacjami i elementami danych wymaganymi do jego wdrożenia? Odpowiedzi na wszystkie te pytania znajdują się w poniższych sekcjach, które opisują podstawowe koncepcje protokołu TCP.

10.2.1 Strumienie danych wejściowych i wyjściowych

Konceptualistyczny Model połączenia polega na tym, że aplikacja przekazuje strumień danych do aplikacji równorzędnej. Jednocześnie może odbierać strumień danych od swojego partnera połączenia. TCP zapewnia pełny dupleks(full duplex) tryb pracy, w którym jednocześnie serwisowany dwa strumienie dane (patrz ryc. 10.2).


Ryż. 10.2. Aplikacje wymieniają strumienie danych.

10.2.2 Segmenty

TCP może konwertować strumień danych opuszczający aplikację do postaci odpowiedniej do przechowywania w datagramach. Jak?

Aplikacja wysyła dane do protokołu TCP, a ten protokół je tam umieszcza bufor wyjściowy(bufor wysyłania). Następnie TCP wycina fragmenty danych z bufora i wysyła je, dodając nagłówek (generuje to segmenty- człon). Na ryc. 10.3 pokazuje, jak dane z bufor wyjściowy TCP jest pakowany w segmenty. TCP przekazuje segment do IP w celu dostarczenia jako oddzielny datagram. Pakowanie danych na fragmenty o odpowiedniej długości zapewnia wydajne przekazywanie, dlatego protokół TCP przed utworzeniem segmentu zaczeka, aż w buforze wyjściowym będzie dostępna odpowiednia ilość danych.


Ryż. 10.3 Tworzenie segmentu TCP

10.2.3 Pchanie

Jednak dużych ilości danych często nie da się zastosować w rzeczywistych zastosowaniach. Na przykład, gdy program kliencki użytkownika końcowego inicjuje sesję interaktywną ze zdalnym serwerem, użytkownik wprowadza jedynie polecenia (następnie naciskając klawisz Powrót).

Program kliencki użytkownika potrzebuje protokołu TCP, aby wiedzieć, że dane są wysyłane do zdalnego hosta i aby natychmiast wykonać tę operację. W tym przypadku jest używany wypychanie(naciskać).

Jeśli przyjrzysz się operacjom w sesji interaktywnej, znajdziesz wiele segmentów z małą ilością danych, a ponadto wyskakiwanie można znaleźć w prawie każdym segmencie danych. Jednak podczas przesyłania plików nie należy stosować wypychania (z wyjątkiem ostatniego segmentu), a protokół TCP będzie w stanie najskuteczniej spakować dane w segmenty.

10.2.4 Pilne dane

Model przekazywania danych aplikacji obejmuje uporządkowany strumień bajtów przesyłany do miejsca docelowego. Odnosząc się ponownie do przykładu sesji interaktywnej, załóżmy, że użytkownik nacisnął klawisz uwaga(uwaga) lub przerwa(przerywać). Zdalna aplikacja musi mieć możliwość pominięcia zakłócających bajtów i możliwie najszybszej reakcji na naciśnięcie klawisza.

Mechanizm pilne dane(pilne dane) oznacza informację specjalną w segmencie jako pilny. W ten sposób TCP informuje swojego partnera, że ​​segment zawiera pilne dane i może wskazać, gdzie się on znajduje. Partner musi jak najszybciej przekazać tę informację do aplikacji docelowej.

10.2.5 Porty aplikacji

Klient musi określić usługę, do której chce uzyskać dostęp. Odbywa się to poprzez podanie adresu IP usługi hosta i numeru jej portu TCP. Podobnie jak UDP, numery portów TCP mieszczą się w zakresie od 0 do 65535. Porty w zakresie od 0 do 1023 nazywane są dobrze znanymi i służą do uzyskiwania dostępu do standardowych usług.

Kilka przykładów dobrze znanych portów i odpowiadających im zastosowań przedstawiono w tabeli 10.1. Usługi Wyrzucać(port 9) i naładowany(port 19) to wersje TCP znanych nam już usług poprzez UDP. Należy pamiętać, że ruch do portu 9 protokołu TCP jest całkowicie odizolowany od ruchu do portu 9 protokołu UDP.


Tabela 10.1 Dobrze znane porty TCP i odpowiadające im zastosowania

Port Aplikacja Opis
9 Wyrzucać Anuluj wszystkie przychodzące dane
19 Naładowany Generator znaków. Wymiana strumienia znaków
20 Dane FTP Port przesyłania danych FTP
21 FTP Port dla dialogu FTP
23 TELNET Port do zdalnej rejestracji przez Telnet
25 SMTP Port protokołu SMTP
110 POP3 Usługa pobierania próbek poczty dla komputerów osobistych
119 NNTP Dostęp do aktualności w Internecie

A co z portami używanymi przez klientów? W rzadkich przypadkach klient nie działa przez dobrze znany port. Jednak w takich sytuacjach chcąc otworzyć połączenie często prosi system operacyjny o przypisanie mu nieużywanego i niezarezerwowanego portu. Po zakończeniu połączenia klient musi zwrócić ten port, po czym port będzie mógł zostać ponownie wykorzystany przez innego klienta. Ponieważ w puli niezarezerwowanych numerów znajduje się ponad 63 000 portów TCP, ograniczenia portów klienta można zignorować.

10.2.6 Adresy gniazd

Jak już wiemy, nazywa się to kombinacją adresu IP i portu do komunikacji gniazdo adresowe. Połączenie TCP jest całkowicie identyfikowane poprzez adres gniazda na każdym końcu połączenia. Na ryc. Rysunek 10.4 przedstawia połączenie pomiędzy klientem o adresie gniazda (128.36.1.24, port = 3358) a serwerem o adresie gniazda (130.42.88.22, port = 21).

Ryż. 10.4. Adresy gniazd

Nagłówek każdego datagramu zawiera źródłowy i docelowy adres IP. Później zobaczysz, że numery portów źródłowego i docelowego są określone w nagłówku segmentu TCP.

Zazwyczaj serwer jest w stanie zarządzać wieloma klientami jednocześnie. Unikalne adresy gniazd serwera są przydzielane jednocześnie wszystkim jego klientom (patrz rys. 10.5).


Ryż. 10,5. Wielu klientów podłączonych do adresów gniazd serwera

Ponieważ datagram zawiera segment połączenia TCP identyfikowany przez adresy IP i porty, serwer może bardzo łatwo śledzić wiele połączeń z klientami.

10.3 Mechanizm niezawodności TCP

W tej sekcji przyjrzymy się mechanizmowi TCP służącemu do niezawodnego dostarczania danych przy jednoczesnym zachowaniu kolejności transmisji i uniknięciu utraty lub powielania.

10.3.1 Numeracja i potwierdzenie

W protokole TCP zastosowano numerację i potwierdzenie (ACK), aby zapewnić niezawodny transfer danych. Schemat numeracji TCP jest dość nietypowy: każdy przesyłane przez połączenie oktet uważa się, że posiada numer seryjny. Nagłówek segmentu TCP zawiera numer kolejny pierwszy oktet danych w tym segmencie.

Odbiorca ma obowiązek potwierdzić otrzymanie danych. Jeśli potwierdzenie nie dotrze w określonym przedziale czasu, dane zostaną ponownie przesłane. Ta metoda nazywa się pozytywne potwierdzenie za pomocą przekaźnika(pozytywne potwierdzenie z retransmisją).

Odbiorca danych TCP dokładnie sprawdza przychodzące numery sekwencyjne, aby sprawdzić, czy dane są odbierane po kolei i czy nie brakuje w nich żadnych części. Ponieważ potwierdzenie może zostać losowo utracone lub opóźnione, do odbiorcy mogą dotrzeć zduplikowane segmenty. Numery sekwencyjne pozwalają zidentyfikować zduplikowane dane, które następnie są odrzucane.

Na ryc. Rysunek 10.6 przedstawia uproszczony widok przekroczenia limitu czasu i retransmisji w protokole TCP.


Ryż. 10.6. Limit czasu i retransmisja w protokole TCP

10.3.2 Pola Port, sekwencja i ACK w nagłówku TCP

Jak pokazano na ryc. 10.7, kilka pierwszych pól nagłówka TCP zapewnia miejsce na wartości portu źródłowego i docelowego, numer kolejny pierwszego bajtu załączonych danych oraz potwierdzenie ACK równe numerowi porządkowemu Następny bajt oczekiwany na drugim końcu. Innymi słowy, jeśli protokół TCP odbierze od swojego partnera wszystkie bajty do 30, pole to będzie miało wartość 31, wskazując segment, który ma zostać przekazany dalej.


Ryż. 10.7. Wartości początkowe w polach nagłówka TCP

Nie można pominąć jednego drobnego szczegółu. Załóżmy, że protokół TCP wysłał bajty od 1 do 50 i nie ma więcej danych do wysłania. Jeśli dane zostaną odebrane od partnera, protokół TCP musi potwierdzić ich otrzymanie, wysyłając nagłówek bez dołączonych do niego danych. Naturalnie nagłówek ten zawiera wartość ACK. W polu sekwencji - wartość wynosi 51, tj. numer następnego bajtu, który zamierza wyślij TCP. Kiedy protokół TCP wyśle ​​kolejne dane, nowy nagłówek TCP będzie również zawierał pole sekwencji o wartości 51.

10.4 Nawiązanie połączenia

W jaki sposób dwie aplikacje łączą się ze sobą? Każdy z nich przed komunikacją wywołuje podprogram tworzący blok pamięci, który posłuży do przechowywania parametrów TCP i IP danego połączenia, np. adresów gniazd, bieżącego numeru sekwencyjnego, początkowej wartości czasu życia itp.

Aplikacja serwerowa oczekuje na pojawienie się klienta, który chcąc uzyskać dostęp do serwera wystawia żądanie mieszanina(połącz), identyfikując adres IP i port serwera.

Jest jedna cecha techniczna. Każda strona zaczyna numerować każdy bajt nie od jednego, ale od losowy numer seryjny(dowiemy się później, dlaczego tak się dzieje). Oryginalna specyfikacja zaleca, aby początkowy numer sekwencyjny był generowany w oparciu o 32-bitowy zewnętrzny zegar, którego wartość zwiększa się co około 4 µs.

10.4.1 Scenariusz połączenia

Procedurę łączenia nazywa się często trójstronnym uzgadnianiem, ponieważ w celu nawiązania połączenia wymieniane są trzy komunikaty - SYN, SYN i ACK.

Podczas nawiązywania połączenia partnerzy wymieniają trzy ważne informacje:

1. Przestrzeń buforowa do odbioru danych

2. Maksymalna ilość danych przesyłanych w przychodzącym segmencie

3. Początkowy numer kolejny używany dla danych wychodzących

Należy pamiętać, że każda ze stron używa operacji 1 i 2 do wskazania granice, w jakich druga strona będzie działać. Komputer osobisty może mieć mały bufor odbiorczy, ale superkomputer może mieć ogromny bufor. Struktura pamięci komputera osobistego może ograniczać przychodzące fragmenty danych do 1 KB, ale superkomputer zarządza większymi segmentami.

Możliwość kontrolowania sposobu, w jaki druga strona wysyła dane, jest ważną cechą, która sprawia, że ​​protokół TCP/IP jest skalowalny.

Na ryc. Rysunek 10.8 przedstawia przykładowy skrypt połączenia. Zaprezentowano bardzo proste początkowe numery porządkowe, aby nie przeciążać rysunku. Należy zauważyć, że na tym rysunku klient może odbierać większe segmenty niż serwer.


Ryż. 10.8. Nawiązanie połączenia

Wykonywane są następujące operacje:

1. Serwer inicjuje się i jest gotowy do połączenia z klientami (ten stan nazywany jest pasywnym otwarciem).

2. Klient żąda od protokołu TCP otwarcia połączenia z serwerem pod określonym adresem IP i portem (ten stan nazywa się aktywnym otwarciem).

3. Klient TCP odbiera początkowy numer sekwencyjny (w tym przykładzie 1000) i wysyła segment synchronizacji(synchronizacja segmentu - SYN). Segment ten zawiera numer kolejny, rozmiar okna odbioru (4K) i rozmiar największego segmentu, jaki klient może odebrać (1460 bajtów).

4. Kiedy nadchodzi sygnał SYN, serwer TCP odbiera kopalnia początkowy numer kolejny (3000). Wysyła segment SYN zawierający początkowy numer kolejny (3000), ACK 1001 (co oznacza, że ​​pierwszy bajt wysłany przez klienta ma numer 1001), rozmiar okna odbioru (4K) i rozmiar największego segmentu, jaki może serwer odebrać (1024 bajty).

5. Klient TCP po odebraniu z serwera komunikatu SYN/ACK odsyła ACK 3001 (pierwszy bajt danych przesłanych przez serwer powinien mieć numer 3001).

6. Klient TCP instruuje swoją aplikację, aby otworzyła połączenie.

7. Serwer TCP po otrzymaniu wiadomości ACK od klienta TCP informuje swoją aplikację o otwarciu połączenia.

Klient i serwer ogłaszają swoje zasady dotyczące odbieranych danych, synchronizują swoje numery sekwencyjne i przygotowują się do wymiany danych. Specyfikacja TCP dopuszcza także inny scenariusz (niezbyt udany), gdy aplikacje równoczesne aktywnie otwierają się nawzajem.

10.4.2 Ustawianie wartości parametrów IP

Żądanie aplikacji nawiązania połączenia może również określać parametry datagramów IP, które będą przenosić dane połączenia. Jeśli nie określono określonej wartości parametru, używana jest wartość domyślna.

Na przykład aplikacja może wybrać żądaną wartość priorytetu IP lub typu usługi. Ponieważ każda z podłączonych stron samodzielnie ustala swój priorytet i rodzaj usługi, teoretycznie wartości te mogą się różnić dla różnych kierunków przepływu danych. Z reguły w praktyce dla każdego kierunku wymiany stosowane są te same wartości.

Jeśli aplikacja obejmuje opcje zabezpieczeń rządowych lub wojskowych, każdy punkt końcowy połączenia musi korzystać z tego samego poziomu zabezpieczeń, w przeciwnym razie połączenie nie zostanie nawiązane.

10.5 Przesyłanie danych

Przesyłanie danych rozpoczyna się po ukończeniu trzyetapowego potwierdzenia utworzenia połączenia (patrz rysunek 10.9). Standard TCP pozwala na włączenie normalnych danych do segmentów potwierdzenia, ale nie zostaną one dostarczone do aplikacji do czasu zakończenia połączenia. Aby uprościć numerowanie, używane są komunikaty 1000-bajtowe. Każdy segment nagłówka TCP ma pole ACK identyfikujące numer sekwencyjny bajtów, który ma zostać odebrany od partnera połączenia.


Ryż. 10.9. Prosta wymiana danych i przepływ ACK

Pierwszy segment wysłany przez klienta zawiera bajty od 1001 do 2000. Jego pole ACK powinno zawierać wartość 3001, która wskazuje numer kolejny bajtów, który ma zostać odebrany z serwera.

Serwer odpowiada klientowi segmentem zawierającym 1000 bajtów danych (zaczynając od numeru 3001). Pole ACK nagłówka TCP będzie wskazywało, że bajty od 1001 do 2000 zostały już pomyślnie odebrane, zatem kolejnym oczekiwanym numerem sekwencyjnym segmentu od klienta powinien być rok 2001.

Następnie klient wysyła segmenty rozpoczynające się od bajtów 2001, 3001 i 4001 w określonej kolejności. Należy pamiętać, że klient nie czeka na potwierdzenie po każdym wysłanym segmencie. Dane przesyłane są do peera aż do zapełnienia jego przestrzeni buforowej (zobaczymy poniżej, że odbiorca może bardzo precyzyjnie określić ilość przesyłanych do niego danych).

Serwer oszczędza przepustowość połączenia, wykorzystując pojedyncze potwierdzenie ACK do wskazania pomyślnego przekazania wszystkich segmentów.

Na ryc. Rysunek 10.10 przedstawia transfer danych po utracie pierwszego segmentu. Po upływie limitu czasu segment jest przesyłany ponownie. Należy pamiętać, że po odebraniu utraconego segmentu odbiorca wysyła pojedyncze potwierdzenie ACK potwierdzające przekazanie obu segmentów.


Ryż. 10.10. Utrata danych i retransmisja

10.6 Zamykanie połączenia

Normalne zakończenie połączenia odbywa się przy użyciu tej samej procedury potrójnego uzgadniania, jak podczas otwierania połączenia. Każda ze stron może rozpocząć zamykanie połączenia według następującego scenariusza:

A:

B:"Cienki".

W:„Ja też skończyłem robotę.”

A:"Cienki".

Załóżmy następujący scenariusz (choć jest on stosowany niezwykle rzadko):

A:„Skończyłem. Nie ma więcej danych do wysłania.”

W:„OK. Są jednak pewne dane…”

W:„Ja też skończyłem robotę.”

A:"Cienki".

W poniższym przykładzie połączenie jest zamykane przez serwer, co często ma miejsce w przypadku połączeń klient-serwer. W tym przypadku po wejściu użytkownika w sesję telnetu Polecenie logout powoduje, że serwer inicjuje żądanie zamknięcia połączenia. W sytuacji pokazanej na ryc. 10.11 wykonywane są następujące czynności:

1. Aplikacja na serwerze informuje protokół TCP o zamknięciu połączenia.

2. Serwer TCP wysyła ostatni segment (Final Segment - FIN), informując swojego partnera, że ​​nie ma już więcej danych do wysłania.

3. TCP klienta wysyła potwierdzenie w segmencie FIN.

4. TCP klienta informuje swoją aplikację, że serwer chce zamknąć połączenie.

5. Aplikacja kliencka informuje swój protokół TCP o zamknięciu połączenia.

6. Klient TCP wysyła komunikat FIN.

7. Serwer TCP odbiera numer FIN od klienta i odpowiada komunikatem ACK.

8. TCP serwera nakazuje swojej aplikacji zamknięcie połączenia.


Ryż. 10.11. Zamykanie połączenia

Obie strony mogą rozpocząć zamykanie transakcji w tym samym czasie. W tym przypadku normalne zamknięcie połączenia zostaje zakończone po wysłaniu przez każdego uczestnika wiadomości ACK.

10.6.1 Nagłe zakończenie

Każda ze stron może zażądać nagłego zakończenia (nagłego zamknięcia) połączenia. Jest to dopuszczalne, gdy aplikacja chce zakończyć połączenie lub gdy protokół TCP wykryje poważny problem z komunikacją, którego nie może rozwiązać samodzielnie. Żądanie nagłego zakończenia następuje poprzez wysłanie jednego lub więcej komunikatów resetujących do partnera, co jest oznaczone określoną flagą w nagłówku TCP.

10.7 Kontrola przepływu

Odbiornik TCP jest ładowany przychodzącym strumieniem danych i określa, ile informacji może przyjąć. To ograniczenie dotyczy nadawcy TCP. Poniższe wyjaśnienie tego mechanizmu ma charakter koncepcyjny i programiści mogą go implementować na różne sposoby w swoich produktach.

Podczas ustanawiania połączenia każdy peer przydziela miejsce na bufor wejściowy połączenia i powiadamia o tym drugą stronę. Zwykle rozmiar bufora wyraża się jako liczbę całkowitą maksymalnych rozmiarów segmentów.

Strumień danych trafia do bufora wejściowego i jest tam zapisywany przed przesłaniem do aplikacji (definiowanej przez port TCP). Na ryc. Rysunek 10.12 przedstawia bufor wejściowy, który może przyjąć 4 KB.


Ryż. 10.12. Okno odbioru bufora wejściowego

Przestrzeń buforowa jest wypełniana w miarę nadejścia danych. Kiedy aplikacja odbierająca pobiera dane z bufora, zwolnione miejsce staje się dostępne dla nowych przychodzących danych.

10.7.1 Okno odbioru

Okno odbioru(okno odbioru) - dowolne miejsce w buforze wejściowym, niezajęte jeszcze przez dane. Dane pozostają w buforze wejściowym do czasu wykorzystania ich przez aplikację docelową. Dlaczego aplikacja nie zbiera danych od razu?

Prosty scenariusz pomoże odpowiedzieć na to pytanie. Załóżmy, że klient wysłał plik na serwer FTP działający na bardzo obciążonym komputerze, z którego korzysta wielu użytkowników. Program FTP musi następnie odczytać dane z bufora i zapisać je na dysku. Gdy serwer wykonuje operacje we/wy dysku, program czeka na zakończenie tych operacji. W tym momencie może zostać uruchomiony inny program (na przykład zgodnie z harmonogramem) i podczas ponownego uruchamiania programu FTP w buforze będą już napływać kolejne dane.

Okno odbioru rozciąga się od ostatniego potwierdzonego bajtu do końca bufora. Na ryc. 10.12 najpierw dostępny jest cały bufor i dlatego dostępne jest okno odbioru o rozmiarze 4 KB. Kiedy nadejdzie pierwszy KB, okno odbioru zostanie zmniejszone do 3 KB (dla uproszczenia założymy, że każdy segment ma rozmiar 1 KB, choć w praktyce wartość ta różni się w zależności od potrzeb aplikacji). Pojawienie się kolejnych dwóch segmentów o wielkości 1 KB zmniejszy okno odbioru do 1 KB.

Każde potwierdzenie ACK wysłane przez odbiorcę zawiera informację o aktualnym stanie okna odbiorczego, w zależności od tego, jaki jest regulowany przepływ danych ze źródła.

W większości przypadków rozmiar bufora wejściowego jest ustawiany w momencie rozpoczęcia połączenia, chociaż standard TCP nie określa sposobu zarządzania tym buforem. Bufor wejściowy można zwiększyć lub zmniejszyć, przekazując informację zwrotną nadawcy.

Co się stanie, jeśli nadchodzący segment można umieścić w oknie odbiorczym, ale dotrze on nieprawidłowo? Ogólnie zakłada się, że wszystkie implementacje przechowują przychodzące dane w oknie odbioru i wysyłają potwierdzenie (ACK) tylko dla całego sąsiadującego bloku wielu segmentów. Jest to właściwy sposób, ponieważ w przeciwnym razie odrzucenie danych, które nadeszły w niewłaściwej kolejności, znacznie obniży wydajność.

10.7.2 Okno przesyłania

System przesyłający dane musi śledzić dwie cechy: ilość danych, które zostały już wysłane i potwierdzone, oraz bieżący rozmiar okna odbioru odbiorcy. Aktywny wysyłanie przestrzeni(spacja wysyłania) rozciąga się od pierwszego niepotwierdzonego oktetu do lewej krawędzi bieżącego okna odbioru. Część okno, używany wysyłać, wskazuje, ile dodatkowych danych można przesłać do partnera.

Początkowy numer kolejny i początkowy rozmiar okna odbierania są określane podczas konfiguracji połączenia. Ryż. Rysunek 10.13 ilustruje niektóre cechy mechanizmu przesyłania danych.

1. Nadawca zaczyna z oknem wysyłania o rozmiarze 4 KB.

2. Nadawca wysyła 1 KB. Kopia tych danych jest przechowywana do momentu otrzymania potwierdzenia (ACK), ponieważ może zaistnieć konieczność ich ponownego przesłania.

3. Nadchodzi komunikat ACK dla pierwszego KB i wysyłane są kolejne 2 KB danych. Wynik pokazano w trzeciej części od góry ryc. 10.13. Pamięć 2 KB jest kontynuowana.

4. Na koniec przychodzi potwierdzenie wszystkich przesłanych danych (tj. całość zostaje odebrana przez odbiornik). ACK przywraca rozmiar okna wysyłania do 4 KB.

Ryż. 10.13. Wyślij okno

Warto zwrócić uwagę na kilka ciekawych funkcji:

▪ Nadawca nie czeka na potwierdzenie każdego wysyłanego segmentu danych. Jedynym ograniczeniem przesyłania jest rozmiar okna odbioru (na przykład nadawca może przesyłać tylko segmenty jednobajtowe o wielkości 4 KB).

▪ Załóżmy, że nadawca wysyła dane w kilku bardzo krótkich segmentach (na przykład 80 bajtów). W takim przypadku dane można przeformatować w celu efektywniejszej transmisji (np. w pojedynczy segment).

Nagłówek TCP 10.8

Na ryc. Rysunek 10.14 przedstawia format segmentu (nagłówek i dane TCP). Nagłówek zaczyna się od identyfikatorów portu źródłowego i docelowego. Następne następne pole numer seryjny(numer kolejny) wskazuje pozycję w wychodzącym strumieniu danych, którą zajmuje ten segment. Pole POTWIERDŹ(potwierdzenie) zawiera informację o oczekiwanym kolejnym segmencie, który powinien pojawić się w wejściowym strumieniu danych.


Ryż. 10.14. Segment TCP

Jest sześć flag:

Pole przesunięcia danych(Data Offset) zawiera rozmiar nagłówka TCP w słowach 32-bitowych. Nagłówek TCP musi kończyć się na granicy 32-bitowej.

10.8.1 Opcja maksymalnego rozmiaru segmentu

Parametr „maksymalny rozmiar segmentu”(maksymalny rozmiar segmentu - MSS) służy do zadeklarowania największej porcji danych, która może zostać zaakceptowana i przetworzona przez system. Jednak nazwa jest nieco niedokładna. Zwykle w TCP człon traktowane jako nagłówek plus dane. Jednakże maksymalny rozmiar segmentu zdefiniowana jako:

Rozmiar największego datagramu, jaki można odebrać, wynosi 40

Innymi słowy, MSS odzwierciedla to, co najlepsze ładunek w odbiorniku, gdy nagłówki TCP i IP mają długość 20 bajtów. Jeśli istnieją dodatkowe parametry, ich długość należy odjąć od całkowitego rozmiaru. Dlatego ilość danych, jaką można przesłać w segmencie, definiuje się jako:

Podana wartość MSS + 40 – (suma długości nagłówków TCP i IP)

Uczestnicy zazwyczaj wymieniają wartości MSS w początkowych wiadomościach SYN podczas otwierania połączenia. Jeśli system nie ogłasza wartości maksymalnej wielkości segmentu, używana jest wartość domyślna 536 bajtów.

Maksymalny rozmiar segmentu jest kodowany jako 2-bajtowe wprowadzenie, po którym następuje 2-bajtowa wartość, tj. największa wartość będzie wynosić 2 16 -1 (65 535 bajtów).

MSS nakłada poważne ograniczenia na dane przesyłane w protokole TCP: odbiorca nie będzie w stanie przetworzyć dużych wartości. Nadawca korzysta jednak z segmentów mniejszy rozmiar, ponieważ wielkość MTU na trasie jest również określana dla połączenia.

10.8.2 Używanie pól nagłówka w żądaniu połączenia

Pierwszy segment wysłany w celu otwarcia połączenia ma flagę SYN o wartości 1 i flagę ACK o wartości 0. Początkowy segment SYN to jedyny segment posiadający pole ACK o wartości 0. Należy pamiętać, że narzędzia bezpieczeństwa używają tej funkcji do identyfikowania żądań wejściowych dla sesji TCP.

Pole numer seryjny zawiera początkowy numer kolejny(początkowy numer kolejny), pole okno - początkowy rozmiar okno odbiorcze. Jedynym aktualnie zdefiniowanym parametrem protokołu TCP jest maksymalny rozmiar segmentu (jeśli nie jest określony, używana jest wartość domyślna 536 bajtów), jaki protokół TCP oczekuje. Wartość ta zajmuje 32 bity i zazwyczaj jest obecna w polu żądania połączenia opcje(Opcja). Nagłówek TCP zawierający wartość MSS ma długość 24 bajtów.

10.8.3 Używanie pól nagłówka w odpowiedzi na żądanie połączenia

W odpowiedzi udzielonej na żądanie połączenia obie flagi (SYN i ACK) są równe 1. System odpowiadający wskazuje w odpowiednim polu początkowy numer kolejny, a w polu rozmiar okna odbioru Okno. Maksymalny rozmiar segmentu, jakiego odbiorca chce użyć, jest zwykle określany w odpowiedzi na żądanie połączenia (w pliku opcje). Wartość ta może różnić się od wartości strony żądającej połączenia, tj. można zastosować dwie różne wartości.

Żądanie połączenia można odrzucić, podając w odpowiedzi flagę resetowania (RST) o wartości 1.

10.8.4 Wybór początkowego numeru sekwencyjnego

Specyfikacja TCP zakłada, że ​​podczas nawiązywania połączenia każda ze stron dokonuje wyboru początkowy numer kolejny(w oparciu o bieżącą wartość 32-bitowego wewnętrznego timera). Jak to się robi?

Wyobraźmy sobie, co się stanie, jeśli system się załamie. Załóżmy, że użytkownik otworzył połączenie tuż przed awarią i wysłał niewielką ilość danych. Po odzyskaniu system nie pamięta już niczego, co zostało zrobione przed awarią, w tym już rozpoczętych połączeń i przypisanych numerów portów. Użytkownik ponownie nawiązuje połączenie. Numery portów nie odpowiadają pierwotnym przypisaniom, a niektóre z nich mogą być już używane przez inne połączenia nawiązane kilka sekund przed awarią.

Dlatego druga strona na samym końcu połączenia może nie wiedzieć, że jej partner uległ awarii i został następnie przywrócony. Wszystko to doprowadzi do poważnych zakłóceń, szczególnie gdy przejście starych danych przez sieć i zmieszanie się z danymi z nowo utworzonego połączenia zajmie dużo czasu. Wybór timera startu z aktualizacją (świeży start) eliminuje takie problemy. Stare dane będą miały inną numerację niż zakres numerów sekwencyjnych nowego połączenia. Hakerzy, fałszując źródłowy adres IP zaufanego hosta, próbują uzyskać dostęp do komputerów, podając w wiadomości przewidywalny początkowy numer kolejny. Kryptograficzna funkcja mieszająca oparta na kluczach wewnętrznych zapewnia najlepszą metodę wybierania bezpiecznych nasion.

10.8.5 Typowe zastosowania pól

Podczas przygotowywania nagłówka TCP do transmisji w polu wskazany jest numer kolejny pierwszego oktetu przesyłanych danych numer seryjny(Numer sekwencji).

W polu wpisuje się numer kolejnego oktetu oczekiwanego od partnera połączenia potwierdzenie(Numer potwierdzenia), gdy bit ACK jest ustawiony na 1. Pole okno(Okno) jest przeznaczone dla bieżącego rozmiaru okna odbierającego. To pole zawiera liczba bajtów z numeru potwierdzenia, które można odebrać. Należy pamiętać, że ta wartość pozwala na precyzyjną kontrolę przepływu danych. Używając tej wartości, peer wskazuje aktualny stan okna odbioru podczas sesji wymiany.

Jeśli aplikacja określa operację push w protokole TCP, flaga PUSH jest ustawiana na 1. Odbierający protokół TCP MUSI odpowiedzieć na tę flagę, szybko dostarczając dane do aplikacji, gdy tylko nadawca chce je przesłać dalej.

Flaga URGENT, gdy jest ustawiona na 1, oznacza pilny transfer danych, a odpowiadający jej wskaźnik musi odnosić się do ostatniego oktetu pilnych danych. Typowym zastosowaniem pilnych danych jest wysyłanie sygnałów o przerwaniu lub przerwaniu z terminala.

Pilne dane są często wywoływane informacje pozapasmowe(poza pasmem). Termin ten jest jednak nieprecyzyjny. Pilne dane są wysyłane w normalnym strumieniu TCP, chociaż poszczególne implementacje mogą mieć specjalne mechanizmy sygnalizujące aplikacji, że nadeszły pilne dane, a aplikacja musi sprawdzić zawartość pilnych danych, zanim dotrą wszystkie bajty komunikatu.

Flaga RESET jest ustawiana na 1, gdy połączenie powinno zostać zakończone w sposób nieprawidłowy. Ta sama flaga jest ustawiana w odpowiedzi, gdy nadchodzi segment, który nie jest powiązany z żadnym z bieżących połączeń TCP.

Dla komunikatów o zamknięciu połączenia flaga FIN jest ustawiona na 1.


10.8.6 Suma kontrolna

Suma kontrolna IP dotyczy tylko nagłówka IP, natomiast suma kontrolna TCP jest obliczana dla całego segmentu oraz pseudonagłówka utworzonego z nagłówka IP. Podczas obliczania sumy kontrolnej TCP odpowiednie pole ma wartość 0. Na rys. Rysunek 10.15 przedstawia pseudonagłówek, który bardzo przypomina ten używany w sumie kontrolnej UDP.


Ryż. 10.15. Pole pseudonagłówka jest uwzględniane w sumie kontrolnej protokołu TCP

Długość protokołu TCP oblicza się, dodając długość nagłówka TCP do długości danych. Suma kontrolna TCP wynosi obowiązkowy, a nie jak UDP. Suma kontrolna nadchodzącego segmentu jest najpierw obliczana przez odbiorcę, a następnie porównywana z zawartością pola sumy kontrolnej nagłówka TCP. Jeśli wartości nie są zgodne, segment jest odrzucany.

10.9 Przykład segmentu TCP

Ryż. 10.16, protokół pracy analizatora Sniffer z Network General to sekwencja segmentów TCP. Pierwsze trzy segmenty ustanawiają połączenie pomiędzy klientem a serwerem Telnet. Ostatni segment zawiera 12 bajtów danych.


Ryż. 10.16. Wyświetlanie nagłówka TCP przez analizator Sniffer

Analizator Sniffer konwertuje większość wartości do postaci dziesiętnej. Jednak wartości flag są wyprowadzane w postaci szesnastkowej. Flaga o wartości 12 reprezentuje 010010. Suma kontrolna jest również wyświetlana w postaci szesnastkowej.

10.10 Obsługa sesji

10.10.1 Sondowanie okna

Szybki nadawca i wolny odbiorca mogą utworzyć okno odbioru o rozmiarze 0 bajtów. Wynik ten nazywa się zamknięcie okna(Zamknij okno). Gdy zwolni się miejsce na aktualizację rozmiaru okna odbioru, używane jest potwierdzenie ACK. Jeżeli jednak taka wiadomość zaginie, obie strony będą musiały czekać w nieskończoność.

Aby uniknąć takiej sytuacji, nadawca zestawia możliwy do zapisania timer(utrzymuj timer) podczas zamykania okna tymczasowego. Wartość timera to limit czasu retransmisji. Po upływie czasu segment jest wysyłany do partnera wykrywanie okna(sonda okienna; niektóre implementacje obejmują również dane). Sondowanie powoduje, że peer odsyła potwierdzenie ACK, które raportuje bieżący stan okna.

Jeśli okno nadal ma zerowy rozmiar, wartość zapisywanego licznika czasu jest podwajana. Proces ten powtarza się, aż licznik czasu osiągnie maksymalnie 60 sekund. TCP będzie nadal wysyłał komunikaty sondujące co 60 sekund, aż do otwarcia okna, zakończenia procesu przez użytkownika lub przekroczenia limitu czasu aplikacji.

10.11 Zakończenie sesji

10.11.1 Przerwa na żądanie

Partner połączenia może ulec awarii lub zostać całkowicie przerwany z powodu wadliwej bramy lub łącza. Aby zapobiec retransmisji danych w protokole TCP, istnieje kilka mechanizmów.

Kiedy protokół TCP osiągnie pierwszy próg retransmisji, informuje IP, aby sprawdził uszkodzony router i jednocześnie informuje aplikację, że wystąpił problem. TCP kontynuuje przekazywanie danych aż do osiągnięcia drugiego progu przed zwolnieniem połączenia.

Oczywiście, zanim to nastąpi, może pojawić się komunikat ICMP wskazujący, że miejsce docelowe jest z jakiegoś powodu nieosiągalne. W niektórych implementacjach, nawet po tym, protokół TCP będzie kontynuował próby uzyskania dostępu do miejsca docelowego, aż do upłynięcia limitu czasu (w tym momencie problem może zostać rozwiązany). Następnie aplikacja zostaje poinformowana, że ​​punkt docelowy jest nieosiągalny.

Aplikacja może ustawić własny limit czasu na dostarczenie danych i wykonać własne operacje po upływie tego interwału. Zazwyczaj połączenie zostaje zakończone.

10.11.2 Utrzymywanie połączenia

Gdy niekompletne połączenie wymaga przesyłania danych przez dłuższy czas, staje się nieaktywne. W okresie bezczynności sieć może ulec awarii lub fizyczne linie komunikacyjne mogą zostać przerwane. Gdy tylko sieć zacznie ponownie działać, partnerzy będą kontynuować wymianę danych bez przerywania sesji komunikacyjnej. Strategia ta była zgodna z wymogami Ministerstwa Obrony Narodowej.

Jednak każde połączenie - aktywne lub nieaktywne - zajmuje dużo pamięci komputera. Niektórzy administratorzy muszą zwrócić niewykorzystane zasoby do systemów. Dlatego wiele implementacji protokołu TCP może wysyłać komunikaty o utrzymanie połączenia(kee-alive), która testuje nieaktywne połączenia. Wiadomości takie są okresowo wysyłane do partnera w celu sprawdzenia jego istnienia w sieci. Odpowiedzią powinny być wiadomości ACK. Korzystanie z komunikatów podtrzymujących jest opcjonalne. Jeśli system ma taką możliwość, aplikacja może ją obejść przy użyciu własnych środków. Szacowany okres domyślny Limit czasu konserwacji połączenia wynosi pełne dwie godziny!

Pamiętajmy, że aplikacja może ustawić swój własny timer, według którego na swoim poziomie podejmie decyzję o zakończeniu połączenia.

10.12 Wydajność

Jak wydajny jest protokół TCP? Na wydajność zasobów wpływa wiele czynników, z których najważniejsze to pamięć i przepustowość (patrz rysunek 10.17).


Ryż. 10.17. Współczynniki wydajności protokołu TCP

Przepustowość i opóźnienia używanej sieci fizycznej znacznie ograniczają przepustowość. Niska jakość przekazywania danych skutkuje dużą liczbą odrzuconych datagramów, co powoduje retransmisje i w konsekwencji zmniejsza wydajność przepustowości.

Strona odbiorcza musi zapewniać wystarczającą przestrzeń buforową, aby umożliwić nadawcy wysyłanie danych bez zakłóceń. Jest to szczególnie ważne w przypadku sieci o dużych opóźnieniach, w których odstęp czasu między wysłaniem danych a otrzymaniem potwierdzenia (oraz negocjowaniem rozmiaru okna) upływa długo. Aby utrzymać stały przepływ danych ze źródła, strona odbiorcza musi mieć okno o wielkości co najmniej iloczynu przepustowości i opóźnienia.

Na przykład, jeśli źródło może wysyłać dane z szybkością 10 000 bajtów/s, a powrót potwierdzenia ACK zajmuje 2 sekundy, wówczas druga strona musi zapewnić okno odbiorcze o rozmiarze co najmniej 20 000 bajtów, w przeciwnym razie przepływ danych nie będzie możliwy. być ciągły. Bufor odbiorczy o wielkości 10 000 bajtów zmniejszy przepustowość o połowę.

Innym ważnym czynnikiem wpływającym na wydajność jest zdolność hosta do reagowania na zdarzenia o wysokim priorytecie i szybkiego wykonywania przełączanie kontekstu, tj. zakończyć niektóre operacje i przejść do innych. Host może interaktywnie obsługiwać wielu użytkowników lokalnych, wsadowe procesy w tle i dziesiątki jednoczesnych połączeń komunikacyjnych. Przełączanie kontekstu umożliwia obsługę wszystkich tych operacji przy jednoczesnym ukrywaniu obciążenia systemu. Implementacje integrujące protokół TCP/IP z jądrem systemu operacyjnego mogą znacznie zmniejszyć obciążenie związane z przełączaniem kontekstu.

Zasoby procesora komputera są wymagane do operacji przetwarzania nagłówka TCP. Jeśli procesor nie może szybko obliczyć sum kontrolnych, prowadzi to do zmniejszenia prędkości przesyłania danych w sieci.

Ponadto programiści powinni dążyć do uproszczenia konfiguracji ustawień protokołu TCP, aby administrator sieci mógł je skonfigurować zgodnie z lokalnymi wymaganiami. Na przykład możliwość dostosowania wielkości bufora do przepustowości sieci i opóźnień znacząco poprawi wydajność. Niestety wiele wdrożeń nie zwraca wystarczającej uwagi na tę kwestię i sztywno programuje parametry komunikacji.

Załóżmy, że środowisko sieciowe jest idealne: zasobów jest wystarczających, a przełączanie kontekstów odbywa się szybciej niż kowboje wyciągający rewolwery. Czy zostanie osiągnięta doskonała wydajność?

Nie zawsze. Jakość tworzenia oprogramowania TCP również ma znaczenie. Na przestrzeni lat w różnych implementacjach protokołu TCP zdiagnozowano i rozwiązano wiele problemów z wydajnością. Można uznać, że najlepszym oprogramowaniem będzie takie, które będzie zgodne z RFC 1122, który określa wymagania dla warstwy komunikacyjnej hostów internetowych.

Równie ważny jest wyjątek oraz zastosowanie algorytmów Jacobsona, Kerna i Partridge’a (te interesujące algorytmy zostaną omówione poniżej).

Twórcy oprogramowania mogą zyskać znaczne korzyści tworząc programy eliminujące niepotrzebne transfery niewielkich ilości danych oraz posiadające wbudowane timery zwalniające zasoby sieciowe, które nie są aktualnie używane.

10.13 Algorytmy poprawy wydajności

Przechodząc do poznania dość złożonej części protokołu TCP, przyjrzymy się mechanizmom zwiększania wydajności i rozwiązywania problemów ze zmniejszoną przepustowością. W tej części omówiono następujące kwestie:

Powolny start(wolny start) zapobiega wykorzystaniu dużej części ruchu sieciowego w nowej sesji, co może skutkować stratami.

■ Wyleczyć syndrom „nieświadomego okna”.(syndrom głupiego okna) zapobiega przeciążaniu sieci wiadomościami przez źle zaprojektowane aplikacje.

Opóźnione potwierdzenie(opóźnione ACK) zmniejsza przeciążenie poprzez zmniejszenie liczby niezależnych komunikatów potwierdzających przesyłanie danych.

Obliczony limit czasu retransmisji(obliczanie timeoutu retransmisji) opiera się na negocjowaniu rzeczywistego czasu sesji, redukując ilość niepotrzebnych retransmisji, ale nie powoduje dużych opóźnień w naprawdę niezbędnej wymianie danych.

▪ Zablokowanie przekazywania protokołu TCP, gdy przeciążenia w sieci umożliwia routerom powrót do pierwotnego trybu i współdzielenie zasobów sieciowych we wszystkich sesjach.

■ Wysyłka zduplikowane potwierdzenia(zduplikowane potwierdzenie) w przypadku odebrania segmentu poza sekwencją umożliwia równorzędnym retransmisję przed upływem limitu czasu.

10.13.1 Powolny start

Jeśli włączysz jednocześnie wszystkie domowe urządzenia elektryczne w domu, sieć elektryczna zostanie przeciążona. W sieciach komputerowych powolny start zapobiega przepalaniu się bezpieczników sieciowych.

Nowe połączenie, które natychmiast rozpoczyna wysyłanie dużej ilości danych w już zajętej sieci, może prowadzić do problemów. Ideą powolnego startu jest zapewnienie pomyślnego uruchomienia nowego połączenia przy jednoczesnym powolnym zwiększaniu szybkości przesyłania danych w zależności od rzeczywistego obciążenia sieci. Nadawca jest ograniczony rozmiarem okna ładowania, a nie większym oknem odbioru.

Załaduj okno(okno przeciążenia) zaczyna się od rozmiaru 1 segmentu. Dla każdego segmentu z pomyślnie odebranym potwierdzeniem ACK rozmiar okna ładowania zwiększa się o 1 segment, aż pozostanie mniejszy niż okno odbioru. Jeśli sieć nie jest przeciążona, okno ładowania będzie stopniowo osiągać rozmiar okna odbierającego. W normalnych warunkach spedycyjnych rozmiary tych okien będą takie same.

Pamiętaj, że powolny start nie jest taki powolny. Po pierwszym potwierdzeniu rozmiar okna ładowania wynosi 2 segmenty, a po pomyślnym odebraniu potwierdzenia dla dwóch segmentów rozmiar może wzrosnąć do 8 segmentów. Innymi słowy, rozmiar okna rośnie wykładniczo.

Załóżmy, że zamiast otrzymać potwierdzenie, nastąpi przekroczenie limitu czasu. Zachowanie okna ładowania w tym przypadku omówiono poniżej.

10.13.2 Syndrom nieświadomego okna

W pierwszych wdrożeniach protokołu TCP/IP programiści zetknęli się z tym zjawiskiem syndrom „nieświadomego okna”.(Syndrom głupiego okna – SWS), który pojawiał się dość często. Aby zrozumieć zachodzące wydarzenia, rozważ następujący scenariusz, który prowadzi do niepożądanych konsekwencji, ale jest całkiem możliwy:

1. Aplikacja wysyłająca szybko wysyła dane.

2. Aplikacja odbierająca odczytuje 1 bajt danych z bufora wejściowego (czyli powoli).

3. Bufor wejściowy po odczycie szybko się zapełnia.

4. Aplikacja odbierająca odczytuje 1 bajt, a protokół TCP wysyła potwierdzenie ACK oznaczające „Mam wolne miejsce na 1 bajt danych”.

5. Aplikacja wysyłająca wysyła przez sieć 1-bajtowy pakiet TCP.

6. Odbierający protokół TCP wysyła potwierdzenie o treści „Dziękuję. Otrzymałem pakiet i nie mam już wolnego miejsca”.

7. Aplikacja odbierająca ponownie odczytuje 1 bajt i wysyła potwierdzenie, po czym cały proces się powtarza.

Wolno odbierająca aplikacja długo czeka na przybycie danych i stale wypycha otrzymane informacje do lewej krawędzi okna, wykonując całkowicie bezużyteczną operację, która generuje dodatkowy ruch w sieci.

Rzeczywiste sytuacje nie są oczywiście tak ekstremalne. Szybki nadawca i wolny odbiorca będą wymieniać małe (w stosunku do maksymalnego rozmiaru segmentu) fragmenty danych i przełączać się przez prawie pełne okno odbioru. Na ryc. Rysunek 10.18 pokazuje warunki pojawienia się syndromu „głupiego okna”.


Ryż. 10.18. Okno odbierające bufor z bardzo małą ilością wolnego miejsca

Rozwiązanie tego problemu nie jest trudne. Gdy tylko okno odbioru zostanie zmniejszone do długości mniejszej niż rozmiar docelowy, protokół TCP zaczyna oszukiwać nadawcę. W tej sytuacji TCP nie powinien sygnalizować nadawcy dodatkowy przestrzeń okna, gdy aplikacja odbierająca odczytuje dane z bufora w małych porcjach. Zamiast tego musisz zachować udostępnione zasoby w tajemnicy przed nadawcą, dopóki nie będzie ich wystarczająco dużo. Zalecany jest rozmiar pojedynczego segmentu, chyba że cały bufor wejściowy przechowuje pojedynczy segment (w tym drugim przypadku używany jest rozmiar półbufora). Rozmiar docelowy, jaki powinien raportować protokół TCP, można wyrazić jako:

minimum (1/2 bufora wejściowego, maksymalny rozmiar segmentu)

TCP zaczyna kłamać, gdy rozmiar okna stanie się mniejszy od tego rozmiaru, a prawdę powie, gdy rozmiar okna będzie nie mniejszy niż wartość uzyskana ze wzoru. Należy pamiętać, że nadawca nie ponosi żadnej szkody, ponieważ aplikacja odbierająca i tak nie byłaby w stanie przetworzyć większości oczekiwanych danych.

Zaproponowane rozwiązanie można łatwo zweryfikować w omówionym powyżej przypadku, wysyłając sygnał ACK dla każdego z odebranych bajtów. Ta sama metoda jest odpowiednia również w przypadku, gdy bufor wejściowy może przechowywać kilka segmentów (co często ma miejsce w praktyce). Szybki nadawca zapełni bufor wejściowy, ale odbiorca wskaże, że nie ma wolnego miejsca na umieszczenie informacji i nie otworzy tego zasobu, dopóki jego rozmiar nie osiągnie całego segmentu.

10.13.3 Algorytm Nagle'a

Nadawca, niezależnie od odbiorcy, musi unikać wysyłania bardzo krótkich segmentów, gromadząc dane przed wysłaniem. Algorytm Nagle'a realizuje bardzo prosty pomysł, który pozwala zmniejszyć liczbę krótkich datagramów przesyłanych przez sieć.

Algorytm zaleca opóźnienie przekazywania (i wypychania) danych w oczekiwaniu na potwierdzenie ACK z wcześniej przesłanych danych. Skumulowane dane wysyłane są po otrzymaniu potwierdzenia ACK dla wcześniej wysłanej informacji, albo po otrzymaniu danych do wysłania w ilości pełnego segmentu, albo po upływie limitu czasu. Algorytmu tego nie należy używać w aplikacjach czasu rzeczywistego, które muszą przesyłać dane tak szybko, jak to możliwe.

10.13.4 Opóźnione ACK

Innym mechanizmem poprawiającym wydajność jest metoda opóźnienia ACK. Zmniejszenie liczby potwierdzeń ACK zmniejsza przepustowość, którą można wykorzystać do przekazywania innego ruchu. Jeśli peer TCP nieznacznie opóźnia wysłanie potwierdzenia, wówczas:

s Pojedynczym potwierdzeniem można potwierdzić wiele segmentów.

■ Aplikacja odbierająca może odebrać pewną ilość danych w określonym przedziale czasu, tj. potwierdzenie ACK może zawierać nagłówek wyjściowy i nie wymaga generowania osobnego komunikatu.

Aby uniknąć opóźnień podczas wysyłania strumienia segmentów o pełnej długości (na przykład podczas wymiany plików), potwierdzenie ACK powinno zostać wysłane przynajmniej dla co drugiego pełnego segmentu.

Wiele implementacji wykorzystuje limit czasu 200 ms. Ale opóźnione potwierdzenie ACK nie obniża kursu wymiany. Gdy nadejdzie krótki segment, w buforze wejściowym jest jeszcze wystarczająco dużo wolnego miejsca, aby odebrać nowe dane, a nadawca może kontynuować wysyłanie (dodatkowo ponowne wysyłanie jest zwykle znacznie wolniejsze). Jeżeli nadejdzie cały segment, należy w tej samej sekundzie odpowiedzieć na niego komunikatem ACK.

10.13.5 Przekroczono limit czasu retransmisji

Po wysłaniu segmentu TCP ustawia licznik czasu i monitoruje nadejście potwierdzenia. Jeśli potwierdzenie nie zostanie odebrane w określonym czasie, protokół TCP retransmituje segment (przekaźnik). Jaki powinien być jednak okres przerwy?

Jeśli będzie za krótki, nadawca zaleje sieć, przesyłając niepotrzebne segmenty, które duplikują informacje, które zostały już wysłane. Zbyt duży limit czasu uniemożliwi szybką naprawę segmentów, które faktycznie uległy zniszczeniu podczas przesyłania, co zmniejszy przepustowość.

Jak wybrać odpowiedni limit czasu? Wartość odpowiednia dla szybkiej sieci lokalnej nie będzie odpowiednia dla połączenia zdalnego z wieloma trafieniami. Oznacza to, że zasada „jednej wartości dla dowolnych warunków” jest w sposób oczywisty nieodpowiednia. Co więcej, nawet w przypadku istniejącego konkretnego połączenia warunki sieciowe mogą się zmienić, a opóźnienia mogą wzrosnąć lub zmniejszyć.

Algorytmy Jacobsona, Kerna i Partridge’a (opisane w artykułach , Van Jacobsona i Poprawa szacunków czasu podróży w obie strony w niezawodnych protokołach transportowych, Karn i Partridge) pozwalają protokołowi TCP dostosować się do zmieniających się warunków sieciowych. Algorytmy te są zalecane do stosowania w nowych implementacjach. Przyjrzymy się im pokrótce poniżej.

Zdrowy rozsądek podpowiada, że ​​najlepszą podstawą do oszacowania prawidłowego limitu czasu dla konkretnego połączenia jest monitorowanie Czas cyklu(czas podróży w obie strony) jako odstęp między wysłaniem danych a otrzymaniem potwierdzenia ich otrzymania.

Dobre rozwiązania dla następujących wielkości można uzyskać z podstawowych statystyk (patrz rysunek 10.19), które pomogą obliczyć czas oczekiwania. Nie należy jednak polegać na średnich, ponieważ ponad połowa szacunków będzie większa niż średnia statystyczna. Uwzględniając kilka wartości odstających, możemy uzyskać lepsze szacunki, które uwzględniają rozkład normalny i skracają zbyt długi czas oczekiwania na retransmisję.


Ryż. 10.19. Rozkład czasów cykli

Nie ma potrzeby wykonywania dużej liczby obliczeń, aby uzyskać formalne matematyczne szacunki odchyleń. Możesz użyć dość przybliżonych szacunków opartych na wartości bezwzględnej różnicy między ostatnią wartością a średnim oszacowaniem:

Ostatnie odchylenie = | Ostatni cykl - Średnia |

Aby obliczyć prawidłową wartość limitu czasu, kolejnym czynnikiem, który należy wziąć pod uwagę, jest zmiana czasu cyklu spowodowana bieżącymi warunkami sieci. To, co dzieje się w Internecie w ostatniej chwili, jest ważniejsze niż to, co wydarzyło się godzinę temu.

Załóżmy, że obliczamy średnią cyklu dla bardzo długiej sesji. Niech sieć będzie początkowo lekko obciążona, a my zidentyfikowaliśmy 1000 małych wartości, ale potem nastąpił wzrost ruchu i znaczny wzrost opóźnień.

Na przykład, jeśli 1000 wartości dało średnią statystyczną 170 jednostek, ale następnie zmierzono 50 wartości ze średnią 282, wówczas bieżąca średnia będzie wynosić:

170×1000/1050 + 282×50/1050 = 175

Bardziej rozsądna byłaby wartość wygładzony czas cyklu(Smoothed Round-Trip Time – SRTT), który uwzględnia priorytet późniejszych wartości:

Nowy SRTT = (1 – α)×(stary SRTT) + α×Wartość ostatniego cyklu

Wartość α mieści się w przedziale od 0 do 1. Zwiększ A skutkuje większym wpływem czasu bieżącego cyklu na wygładzoną średnią. Ponieważ komputery mogą szybko wykonać dzielenie przez potęgę 2, przesuwając liczby binarne w prawo, α jest zawsze wybierane jako (1/2)n (zwykle 1/8), więc:

Nowy SRTT = 7/8×Stary SRTT + 1/8×Czas ostatniego cyklu

Tabela 10.2 pokazuje, jak wzór na SRTT dostosowuje się do bieżącej wartości SRTT wynoszącej 230 jednostek, gdy zmiana warunków sieciowych powoduje stopniowe zwiększanie czasu cyklu (zakładając, że nie nastąpi przekroczenie limitu czasu). Wartości z kolumny 3 są używane jako wartości z kolumny 1 dla następnego wiersza tabeli (tj. Podobnie jak stary SRTT).


Tabela 10.2 Obliczanie wygładzonego czasu cyklu

Stary SRT Najnowszy RTT (7/8)×(stary SRTT) + (1/8)×(RTT)
230.00 294 238.00
238.00 264 241.25
241.25 340 253.59
253.59 246 252.64
252.64 201 246.19
246.19 340 257.92
257.92 272 259.68
259.68 311 266.10
266.10 282 268.09
268.09 246 265.33
265.33 304 270.16
270.16 308 274.89
274.89 230 269.28
269.28 328 276.62
276.62 266 275.29
275.29 257 273.00
273.00 305 277.00

Teraz pojawia się kwestia wyboru wartości limitu czasu retransmisji. Analiza wartości czasu cyklu wskazuje na znaczne odchylenie tych wartości od aktualnej wartości średniej. Sensowne jest ustalenie limitu wielkości odchyleń. Dobrą wartość limitu czasu retransmisji (w standardach RFC wartość ta nazywa się Retransmission TimeOut - RTO) podaje poniższy wzór z ograniczeniem wygładzonego odchylenia (SDEV):

T = Limit czasu retransmisji = SRTT + 2×SDEV

T = SRTT + 4×SDEV

Aby obliczyć SDEV, należy najpierw określić wartość bezwzględną odchyłki prądu:

DEW = | Czas ostatniego cyklu - stary SRTT |

Następnie stosuje się wzór wygładzający, aby uwzględnić tę drugą wartość:

Nowy SDEV = 3/4×stary SDEV + 1/4×DEV

Pozostaje jedno pytanie – jakie wartości początkowe przyjąć? Zalecana:

Początkowy limit czasu = 3 s

Początkowy SRTT = 0

Początkowy SDEV = 1,5 s

Van Jacobson zdefiniował szybki algorytm, który bardzo efektywnie oblicza limit czasu retransmisji danych.

10.13.6 Przykład statystyki

Jak skuteczny będzie obliczony powyżej limit czasu? Po wdrożeniu tej wartości zaobserwowano znaczną poprawę wydajności. Przykładem mogą być statystyki zespołu netstat, otrzymane w systemie Tygrys- serwer internetowy, do którego ma dostęp wiele hostów z całego świata.


1510769 pakietów (314955304 bajtów) odebranych kolejno

System Tygrys Retransmitowano mniej niż 2,5% segmentów danych TCP. W przypadku półtora miliona przychodzących segmentów danych (reszta to czyste wiadomości ACK) tylko 0,6% zostało zduplikowanych. Należy wziąć pod uwagę, że poziom strat w danych wejściowych w przybliżeniu odpowiada poziomowi dla segmentów wyjściowych. Zatem marnotrawny ruch retransmisyjny stanowi około 0,6% całkowitego ruchu.

10.13.7 Obliczenia po ponownym przesłaniu

Zaprezentowane powyżej formuły wykorzystują czas cyklu jako odstęp między wysłaniem segmentu a otrzymaniem potwierdzenia jego odbioru. Załóżmy jednak, że w określonym czasie nie otrzymano żadnego potwierdzenia i dane muszą zostać przesłane ponownie.

Algorytm Kerna zakłada, że ​​w tym przypadku nie należy zmieniać czasu cyklu. Bieżąca wygładzona wartość czasu cyklu i wygładzone odchylenie zachowują swoje wartości do czasu otrzymania potwierdzenia o przekazaniu określonego segmentu bez ponownego wysyłania. Od tego momentu obliczenia są wznawiane w oparciu o zapisane wartości i nowe pomiary.

10.13.8 Działania po retransmisji

Ale co się dzieje przed otrzymaniem potwierdzenia? Po retransmisji zachowanie protokołu TCP zmienia się radykalnie, głównie z powodu utraty danych spowodowanej przeciążeniem sieci. W związku z tym odpowiedzią na ponowne przesłanie danych będzie:

▪ Zmniejszona szybkość retransmisji

▪ Zwalczaj przeciążenia sieci poprzez redukcję ogólnego ruchu

10.13.9 Hamowanie wykładnicze

Po retransmisji limit czasu zostaje podwojony. Co się jednak stanie, jeśli licznik czasu ponownie się przepełni? Dane zostaną przesłane ponownie, a okres retransmisji ponownie się podwoi. Proces ten nazywa się hamowanie wykładnicze(wykładnicze wycofanie).

Jeśli awaria sieci będzie się powtarzać, limit czasu zostanie podwojony, aż do osiągnięcia ustawionej wartości maksymalnej (zwykle 1 minuta). Po upływie limitu czasu można wysłać tylko jeden segment. Limit czasu występuje również w przypadku przekroczenia zadanej wartości liczby transferów danych bez otrzymania potwierdzenia.

10.13.10 Zmniejszenie przeciążenia poprzez redukcję danych przesyłanych siecią

Ograniczanie ilości przesyłanych danych jest nieco bardziej złożone niż mechanizmy omówione powyżej. Zaczyna działać, podobnie jak wspomniany już powolny start. Ponieważ jednak ustalono ograniczenie poziomu ruchu, który początkowo może powodować problemy, prędkość wymiany w rzeczywistości spadnie ze względu na wzrost rozmiaru okna ładowania dla jednego segmentu. Musisz ustawić wartości graniczne, aby faktycznie zmniejszyć prędkość wysyłania. Najpierw obliczany jest próg zagrożenia:

Granica – minimum 1/2 (bieżące okno ładowania, okno odbioru partnera)

Jeśli wynikowa wartość składa się z więcej niż dwóch segmentów, jest używana jako granica. W przeciwnym razie rozmiar obramowania jest ustawiony na dwa segmenty. Algorytm pełnego odzyskiwania wymaga:

■ Ustaw rozmiar okna ładowania na jeden segment.

■ Dla każdego otrzymanego potwierdzenia ACK zwiększ rozmiar okna ładowania o jeden segment, aż do osiągnięcia granicy (podobnie jak w przypadku mechanizmu powolnego startu).

▪ Następnie po każdym odebranym potwierdzeniu dodaj mniejszą wartość do okna ładowania, która jest wybierana na podstawie tempa wzrostu na segment w czasie cyklu (wzrost jest obliczany jako MSS/N, gdzie N to rozmiar okna ładowania w segmentach).

Idealny scenariusz może zapewnić uproszczoną reprezentację działania mechanizmu odzyskiwania środków. Załóżmy, że okno odbiorcze partnera (oraz bieżące okno ładowania) miało rozmiar 8 segmentów przed wykryciem limitu czasu, a granicę zdefiniowano jako 4 segmenty. Jeśli aplikacja odbierająca natychmiast odczyta dane z bufora, rozmiar okna odbioru pozostanie 8 segmentów.

▪ Wysłano 1 segment (okno ładowania = 1 segment).

▪ Otrzymano potwierdzenie ACK – wysyłane są 2 segmenty.

▪ Odebrano potwierdzenie ACK dla 2 segmentów – wysłane zostały 4 segmenty (osiągnięto granicę).

▪ Otrzymano potwierdzenie ACK dla 4 segmentów. Wysyłanych jest 5 segmentów.

▪ Otrzymano potwierdzenie dla 5 segmentów. Wysyłanych jest 6 segmentów.

▪ Otrzymano potwierdzenie dla 6 segmentów. Wysyłanych jest 7 segmentów.

▪ Otrzymano potwierdzenie dla 7 segmentów. Wysyłanych jest 8 segmentów (okno ładowania znów ma taką samą wielkość jak okno odbierające).

Ponieważ retransmisja po przekroczeniu limitu czasu wymaga potwierdzenia odbioru wszystkich wysłanych danych, proces jest kontynuowany, aż okno ładowania osiągnie rozmiar okna odbioru. Wydarzenia, które mają miejsce, pokazane są na ryc. 10.20. Rozmiar okna rośnie wykładniczo, podwaja się w okresie powolnego startu i zwiększa się liniowo po osiągnięciu granicy.


Ryż. 10.20. Ograniczanie prędkości spedycji w czasie zatorów

10.13.11 Zduplikowane potwierdzenia

Niektóre implementacje wykorzystują opcjonalną funkcję o nazwie szybko wyślij ponownie(szybka retransmisja) – w celu przyspieszenia ponownej wysyłki danych pod pewnymi warunkami. Jego podstawowa idea polega na tym, że odbiorca wysyła dodatkowe potwierdzenia ACK wskazujące lukę w otrzymanych danych.

Po odebraniu segmentu w niewłaściwej kolejności odbiornik odsyła potwierdzenie ACK wskazujące na pierwszy bajt zaginiony dane (patrz rysunek 10.21).


Ryż. 10.21. Zduplikowane potwierdzenia

Nadawca nie retransmituje danych natychmiast, ponieważ protokół IP może zwykle dostarczyć dane do odbiorcy bez sekwencji wysyłania. Jeśli jednak odebranych zostanie kilka dodatkowych zduplikowanych pakietów ACK danych (na przykład trzy), brakujący segment zostanie wysłany bez oczekiwania na upłynięcie limitu czasu.

Należy pamiętać, że każde zduplikowane potwierdzenie ACK wskazuje odbiór segmentu danych. Kilka zduplikowanych potwierdzeń wskazuje, że sieć jest w stanie dostarczyć wystarczającą ilość danych i dlatego nie jest nadmiernie obciążona. W ramach ogólnego algorytmu następuje niewielkie zmniejszenie rozmiaru okna ładowania w przypadku rzeczywistego wzrostu ruchu sieciowego. W tym przypadku proces radykalnej zmiany rozmiaru podczas przywracania pracy nie jest stosowany.

Zgodnie ze standardem Wymagania gospodarza(wymagania hosta) Podczas wygaszania źródła protokół TCP musi wykonać ten sam powolny start, jak opisano powyżej. Jednak ta wiadomość nie jest ukierunkowana ani skuteczna, ponieważ połączenie odbierające wiadomość może nie generować zbyt dużego ruchu. Aktualna specyfikacja Wymagania routera(wymagania routera) oznacza, że ​​routers nie powinieneś wysyłaj wiadomości o wyłączeniu źródła.

13.10.13 Statystyki TCP

Na koniec przyjrzyjmy się komunikatom statystycznym zespołu netstat, aby zobaczyć, jak działa wiele opisanych powyżej mechanizmów.

Segmenty nazywane są pakietami.
879137 pakietów danych (226966295 bajtów)
Retransmitowano 21815 pakietów danych (8100927 bajtów).
Ponowna wysyłka.
132957 pakietów tylko do potwierdzenia (104216 opóźnionych)
Zwróćmy uwagę na dużą liczbę

opóźnione potwierdzenie.

Próba otwarcia okna

rozmiar zerowy.

Są to komunikaty SYN i FIN.
762469 potwierdzeń (dla 226904227 bajtów)
Sygnał o nadejściu pakietów

poza kolejnością.

1510769 pakietów (314955304 bajtów)
9006 całkowicie zduplikowanych pakietów (867042 bajtów)
Wynik przekroczenia limitu czasu z wartością rzeczywistą

dostarczanie danych.

74 pakiety z pewnym duplikatem. dane (12193 bajtów zduplikowanych)
Dla większej wydajności

niektóre dane zostały przepakowane, aby uwzględnić dodatkowe bajty przy ponownym wysłaniu.

13452 pakietów poza kolejnością (2515087 bajtów)
530 pakietów (8551 bajtów) danych po oknie
Być może te dane były

zawarte w brzmiących wiadomościach.

Po zamknięciu odebrano 402 pakiety
To są kolejne powtórki

wysyłanie.

108 odrzucone ze względu na złe sumy kontrolne
Nieprawidłowa suma kontrolna TCP.
0 odrzucone ze względu na nieprawidłowe pola przesunięcia nagłówka
7 odrzuconych, ponieważ pakiet jest za krótki
14677 nawiązanych połączeń (w tym zaakceptowanych)
Zamknięto 18929 połączeń (w tym 643 zrzuty)
Utracono 4100 połączeń embrionalnych
Zaktualizowano 572187 segmentów rtt (z 587397 prób)
Nieudane próby zmiany

czas cyklu, ponieważ potwierdzenie nie dotarło przed upływem limitu czasu,

26 połączeń zostało zerwanych z powodu przekroczenia limitu czasu rexmit
Kolejne nieudane próby

wysłać ponownie, wskazując utratę połączenia.

Przekroczenia limitu czasu sondowania

okno zerowe.

Limity czasu weryfikacji

zerwane połączenie.

472 połączenia zostały zerwane przez Keepalive

10.14 Zgodność z wymaganiami dewelopera

Obecny standard TCP wymaga, aby implementacje ściśle przestrzegały procedury powolnego startu podczas inicjowania połączenia oraz wykorzystywały algorytmy Kerna i Jacobsona do szacowania limitu czasu ponownego wysłania danych i kontroli obciążenia. Testy wykazały, że mechanizmy te prowadzą do znacznej poprawy wydajności.

Co się stanie, jeśli zainstalujesz system, który nie będzie ściśle przestrzegał tych standardów? Nie zapewni odpowiedniej wydajności własnym użytkownikom i będzie złym sąsiadem dla innych systemów w sieci, uniemożliwiając jego odzyskanie po tymczasowym przeciążeniu i generowanie nadmiernego ruchu, który powoduje utratę datagramów.

10.15 Bariery produktywności

Protokół TCP udowodnił swoją elastyczność, działając w sieciach z szybkością przesyłania setek lub milionów bitów na sekundę. Protokół ten osiągnął dobre wyniki w nowoczesnych sieciach lokalnych o topologiach Ethernet, Token-Ring i Fibre Distributed Data Interface (FDDI), a także w łączach komunikacyjnych o niskiej prędkości lub połączeniach dalekobieżnych (podobnych do łączy satelitarnych).

Protokół TCP zaprojektowano tak, aby reagował na ekstremalne warunki, takie jak przeciążenie sieci. Jednak aktualna wersja protokołu ma funkcje ograniczające wydajność w obiecujących technologiach oferujących przepustowość setek lub tysięcy megabajtów. Aby zrozumieć związane z tym problemy, rozważmy prosty (aczkolwiek nierealistyczny) przykład.

Załóżmy, że przenosząc plik pomiędzy dwoma systemami, chcesz możliwie najefektywniej przeprowadzić ciągły strumień wymiany. Załóżmy, że:

s Maksymalny rozmiar segmentu odbiornika wynosi 1 KB.

■ Okno odbioru - 4 KB.

Przepustowość pozwala na przesłanie dwóch segmentów w ciągu 1 s.

■ Aplikacja odbierająca zużywa dane w momencie ich otrzymania.

■ Komunikaty ACK docierają po 2 sekundach.

Nadawca ma możliwość przesyłania danych w sposób ciągły. Przecież gdy wolumen przydzielony dla okna się zapełni, przychodzi potwierdzenie ACK, umożliwiające wysłanie kolejnego segmentu:

Po 2 s:

ODBIERZ POTWIERDZENIE SEGMENTU 1, MOŻESZ WYSŁAĆ SEGMENT 5.
ODBIERZ POTWIERDZENIE SEGMENTU 2, MOŻESZ WYSŁAĆ SEGMENT 6.
ODBIERZ POTWIERDZENIE SEGMENTU 3, MOŻESZ WYSŁAĆ SEGMENT 7.
ODBIERZ POTWIERDZENIE SEGMENTU 4, MOŻESZ WYSŁAĆ SEGMENT 8.

Po kolejnych 2 s:

ODBIERZ POTWIERDZENIE SEGMENTU 5, MOŻESZ WYSŁAĆ SEGMENT 9.

Jeżeli okno odbioru miałoby tylko 2 KB, nadawca byłby zmuszony odczekać jedną sekundę na dwie przed wysłaniem kolejnych danych. W rzeczywistości, aby utrzymać ciągły strumień danych, okno odbiorcze musi mieć co najmniej:

Okno = szerokość pasma × czas cyklu

Chociaż przykład jest nieco przesadzony (aby podać prostsze liczby), małe okno może powodować problemy w przypadku połączeń satelitarnych o dużych opóźnieniach.

Przyjrzyjmy się teraz, co dzieje się z szybkimi połączeniami. Na przykład, jeśli szerokość pasma i szybkość przesyłania są mierzone przy 10 milionach bitów na sekundę, ale czas cyklu wynosi 100 ms (1/10 sekundy), to w przypadku ciągłego strumienia okno odbioru musi przechowywać co najmniej 1 000 000 bitów, tj. . 125 000 bajtów. Jednak największa liczba, jaką można zapisać w polu nagłówka okna odbioru TCP, to 65 536.

Inny problem pojawia się przy dużych szybkościach transmisji, ponieważ numery sekwencyjne wyczerpią się bardzo szybko. Jeśli łącze może przesyłać dane z szybkością 4 GB/s, to numery sekwencyjne muszą być aktualizowane w ciągu każdej sekundy. Nie będzie możliwości rozróżnienia starych, zduplikowanych datagramów, które były opóźnione o więcej niż sekundę podczas przesyłania przez Internet od nowych, świeżych danych.

Aktywnie prowadzone są nowe badania mające na celu ulepszenie protokołu TCP/IP i wyeliminowanie wspomnianych powyżej przeszkód.

10.16 Funkcje TCP

W tym rozdziale opisano wiele funkcji protokołu TCP. Najważniejsze z nich są wymienione poniżej:

■Powiązanie portów z połączeniami

s Inicjuj połączenia, korzystając z potwierdzenia trzyetapowego

■ Powolny start, aby uniknąć przeciążenia sieci

▪ Segmentacja danych podczas transmisji

■ Numeracja danych

▪ Przetwarzanie przychodzących zduplikowanych segmentów

■ Obliczanie sum kontrolnych

▪ Kontrola przepływu danych przez okno odbioru i okno wysyłania

■ Zakończ połączenie w ustalony sposób

s Zakończenie połączenia

■ Przesyłanie pilnych danych

▪ Pozytywne potwierdzenie ponownej wysyłki

■ Oblicz limit czasu retransmisji

■ Zmniejszony ruch powrotny w przypadku przeciążenia sieci

▪ Sygnalizacja, że ​​segmenty docierają w niewłaściwej kolejności

■ Wykrywanie zamknięcia okna odbiorczego

10.17 Stany TCP

Połączenie TCP przechodzi przez kilka etapów: połączenie jest nawiązywane poprzez wymianę komunikatów, następnie wysyłane są dane, a następnie połączenie jest zamykane poprzez wymianę specjalnych komunikatów. Każdy etap operacji połączenia odpowiada konkretnemu stan to połączenie. Oprogramowanie TCP na każdym końcu połączenia stale monitoruje bieżący stan drugiej strony połączenia.

Poniżej przyjrzymy się pokrótce typowemu przejściu stanu między serwerem a klientem znajdującym się na przeciwległych końcach połączenia. Nie mamy na celu wyczerpującego opisu wszystkich możliwych stanów podczas przesyłania danych. Jest to podane w RFC 793 i dokumencie Wymagania gospodarza.

Podczas nawiązywania połączenia serwer i klient przechodzą przez podobną sekwencję stanów. Stany serwera przedstawiono w Tabeli 10.3, a stany klientów w Tabeli 10.4.


Tabela 10.3 Sekwencja stanu serwera

Status serwera Wydarzenie Opis
ZAMKNIĘTE Stan fikcyjny przed rozpoczęciem nawiązywania połączenia.
Otwarcie pasywne przez aplikację serwerową.
SŁUCHAJ (śledzenie) Serwer oczekuje na połączenie od klienta.
Serwer TCP odbiera komunikat SYN i wysyła sygnał SYN/ACK. Serwer odebrał SYN i wysłał SYN/ACK. Przechodzi do czekania na ACK.
SYN-OTRZYMANO Serwer TCP odbiera potwierdzenie.
ZAŁOŻONE (zainstalowane) Otrzymano potwierdzenie ACK, połączenie otwarte.

Tabela 10.4 Sekwencja stanu klienta

Gdyby partnerzy jednocześnie próbowali nawiązać ze sobą połączenie (co jest niezwykle rzadkie), każdy z nich przeszedłby przez stany ZAMKNIĘTY, SYN-WYSYŁANY, SYN-RECEIVED i USTANOWIONY.

Końcowe strony połączenia pozostają w stanie USTANOWIONYM do momentu rozpoczęcia działania jednej ze stron zamknięcie połączenia poprzez wysłanie segmentu FIN. Podczas normalnego zamknięcia strona inicjująca zamknięcie przechodzi przez stany pokazane w tabeli 10.5. Jej partner przechodzi przez stany przedstawione w tabeli 10.6.


Tabela 10.5 Kolejność stanów strony zamykającej połączenie

Zamykanie stanów pobocznych Wydarzenie Opis
PRZYJĘTY Aplikacja lokalna żąda zamknięcia połączenia.
TCP wysyła FIN/ACK.
FIN-CZEKAJ-1 Strona zamykająca oczekuje na odpowiedź partnera. Przypominamy, że od partnera mogą jeszcze napływać nowe dane.
TCP odbiera potwierdzenie.
FIN-CZEKAJ-2 Strona zamykająca otrzymała ACK od partnera, ale nie otrzymała jeszcze FIN. Strona zamykająca oczekuje na FIN podczas akceptowania przychodzących danych.
TCP odbiera FIN/ACK.
Wysyła potwierdzenie.
CZAS OCZEKIWANIA Połączenie jest utrzymywane w nieokreślonym stanie, aby umożliwić przybycie lub odrzucenie zduplikowanych danych lub zduplikowanych numerów FIN nadal istniejących w sieci. Okres oczekiwania jest dwukrotnie dłuższy od maksymalnego szacowanego czasu życia segmentu.
ZAMKNIĘTE

Tabela 10.6 Kolejność stanów partnera po zamknięciu połączenia

Status partnera Wydarzenie Opis
PRZYJĘTY TCP odbiera FIN/ACK.
ZAMKNIJ-CZEKAJ FIN przybył.
TCP wysyła potwierdzenie.
TCP oczekuje, że jego aplikacja zamknie połączenie. W tym momencie aplikacja może wysyłać dość dużą ilość danych.
Aplikacja lokalna inicjuje zamknięcie połączenia.
TCP wysyła FIN/ACK.
OSTATNIE POK TCP czeka na ostateczne potwierdzenie.
TCP odbiera potwierdzenie.
ZAMKNIĘTE Wszystkie informacje o połączeniu zostały usunięte.

10.17.1 Analiza stanów połączeń TCP

Zespół netstat -an pozwala sprawdzić aktualny stan połączenia. Połączenia w stanach pokazano poniżej słuchaj, uruchamianie, ustalanie, zamykanie I Czas oczekiwania.

Należy pamiętać, że numer portu połączenia jest podany na końcu każdego adresu lokalnego i zewnętrznego. Można zobaczyć, że istnieje ruch TCP zarówno w kolejce wejściowej, jak i wyjściowej.

Pro Recv-Q Wyślij-Q Adres lokalny Adres zagraniczny (stan)
Tcp 0 0 128.121.50.145.25 128.252.223.5.1526 SYN_RCVD
Tcp 0 0 128.121.50.145.25 148.79.160.65.3368 USTANOWIONO
Tcp 0 0 127.0.0.1.1339 127.0.0.1.111 CZAS_oczekiwania
Tcp 0 438 128.121.50.145.23 130.132.57.246.2219 USTANOWIONO
Tcp 0 0 128.121.50.145.25 192.5.5.1.4022 CZAS_oczekiwania
Tcp 0 0 128.121.50.145.25 141.218.1.100.3968 CZAS_oczekiwania
Tcp 0 848 128.121.50.145.23 192.67.236.10.1050 USTANOWIONO
Tcp 0 0 128.121.50.145.1082 128.121.50.141.6000 USTANOWIONE
Tcp 0 0 128.121.50.145.1022 128.121.50.141.1017 USTANOWIONO
Tcp 0 0 128.121.50.145.514 128.121.50.141.1020 CLOSE_WAIT
Tcp 0 1152 128.121.50.145.119 192.67.239.23.3572 USTANOWIONO
Tcp 0 0 128.121.50.145.1070 192.41.171.5.119 CZAS_oczekiwania
Tcp 579 4096 128.121.50.145.119 204.143.19.30.1884 USTANOWIONE
Tcp 0 0 128.121.50.145.119 192.67.243.13.3704 USTANOWIONO
Tcp 0 53 128.121.50.145.119 192.67.236.218.2018 FIN_WAIT_1
Tcp 0 0 128.121.50.145.119 192.67.239.14.1545 USTANOWIONO

10.18 Uwagi dotyczące wdrożeń

Od samego początku protokół TCP miał za zadanie współpracować ze sprzętem sieciowym różnych producentów. Specyfikacja TCP nie określa dokładnie, jak powinny działać wewnętrzne struktury implementacyjne. Te pytania pozostawiamy programistom, których zadaniem jest znalezienie najlepszych mechanizmów dla każdej konkretnej implementacji.

Nawet RFC 1122 (dokument Wymagania gospodarza — wymagania dla gospodarzy) pozostawia wystarczającą swobodę zmian. Każda z zaimplementowanych funkcji charakteryzuje się pewnym poziomem kompatybilności:

■ MAJ (dozwolony)

■ NIE MOŻE

Niestety czasami zdarzają się produkty, które nie spełniają wymagań MUST. W rezultacie użytkownicy odczuwają niedogodności związane ze zmniejszoną wydajnością.

Niektóre dobre praktyki wdrożeniowe nie są ujęte w standardach. Na przykład bezpieczeństwo można poprawić, ograniczając użycie dobrze znanych portów przez uprzywilejowane procesy w systemie, jeśli lokalny system operacyjny obsługuje tę metodę. Aby poprawić wydajność, implementacje powinny jak najmniej kopiować i przenosić wysyłane lub pobierane dane.

Standardowy interfejs programowania aplikacji nieokreślony(jak również politykę bezpieczeństwa), aby pozostała wolna przestrzeń do eksperymentowania z różnymi zestawami narzędzi programowych. Może to jednak spowodować użycie różnych interfejsów programistycznych na każdej platformie i uniemożliwić przenoszenie aplikacji między platformami.

W rzeczywistości programiści opierają swoje zestawy narzędzi na interfejsie programowania Socket zapożyczonym od Berkeley. Znaczenie interfejsu oprogramowania wzrosło wraz z pojawieniem się WINSock (Windows Socket), co doprowadziło do rozpowszechnienia się nowych aplikacji komputerowych, które mogą działać na dowolnym interfejsie WINSock zgodnym ze stosem TCP/IP.

10.19 Dalsza lektura

Oryginalny standard TCP jest zdefiniowany w RFC 793. Aktualizacje, poprawki i wymagania dotyczące zgodności są omówione w RFC 1122. Kern and Partridge opublikowali artykuł Poprawa szacunków dotyczących podróży w obie strony w niezawodnych protokołach transportowych W magazynie Postępowanie ACM SIGCOMM 1987. artykuł Jacobsona Unikanie i kontrola zatorów komunikacyjnych pojawił się w Materiały z warsztatów ACM SIGCOMM 1988. Jacobson wydał także kilka dokumentów RFC zmieniających algorytmy wydajności.