Transport część 2: protokół TCP Sieci komputerowe Wykład 6 Marcin Bieńkowski
Protokoły w Internecie warstwa aplikacji HTTP warstwa transportowa SMTP TCP warstwa sieciowa warstwa łącza danych warstwa fizyczna DNS NTP UDP IP Ethernet kable miedziane PPP 802.11 (WiFi) światłowód "2 DSL MPLS fale radiowe
W poprzednim odcinku: niezawodny transport Segmentacja Algorytmy niezawodnego dostarczania danych: stop-and-wait, okno przesuwne nadawcy. Potwierdzanie: go-back-n, selektywne, skumulowane. Kontrola przepływu: okno odbiorcy, odbiorca wysyła rozmiar oferowanego okna reguluje rozmiar okna nadawcy. TCP: okno przesuwne + potwierdzanie skumulowane + kontrola przepływu. "3
Przypomnienie: przesuwne okno nadawcy LAR = Last ACK received 1 2 3 wysłane i potwierdzone 4 LAR + SWS 5 6 7 8 wysłane ale niepotwierdzone utrzymujemy dla nich licznik czasu 9 10 niewysłane Akcje: Otrzymanie ACK sprawdzamy, czy możemy przesunąć okno. Przesunięcie okna wysyłamy dodatkowe segmenty. Timeout dla (niepotwierdzonego) segmentu wysyłamy go ponownie. "4
Przypomnienie: okno odbiorcy, potwierdzanie skumulowane Wysyłanie ACK: Wysyłamy tylko jeśli otrzymamy segment S LFRead + RWS W razie potrzeby aktualizujemy LFRcvd (przesuwamy okno w prawo) a następnie wysyłamy ACK dla LFRcvd. "5
Przypomnienie: okno odbiorcy, potwierdzanie skumulowane LFRead + RWS LFRcvd (last frame received) 1 2 3 4 6 7 LFRead (last frame read) odebrane (i potwierdzone) ale nieprzeczytane przez aplikację odebrane, potwierdzone, przeczytane przez aplikację Wysyłanie ACK: Wysyłamy tylko jeśli otrzymamy segment S LFRead + RWS W razie potrzeby aktualizujemy LFRcvd (przesuwamy okno w prawo) a następnie wysyłamy ACK dla LFRcvd. "5
Przypomnienie: oferowane okno Odbiorca: Oferowane okno = wolne miejsce w buforze Oferowane okno wysyłane nadawcy (zazwyczaj razem z ACK). Np.: pakiety potwierdzane, ale aplikacja wolno czyta oferowane okno jest małe. 1 2 3 4 6 7 Nadawca: Zmienia SWS (rozmiar swojego okna) na rozmiar oferowanego okna. Nie wysyła danych, na które odbiorca nie ma miejsca. 1 2 3 4 5 6 "6 7 8 9 10
Segment TCP 0 7 8 15 16 23 24 31 port źródłowy port docelowy numer sekwencyjny (numer pierwszego bajtu w segmencie) numer ostatniego potwierdzanego bajtu + 1 offset 000 ECN U-A-P-R-S-F oferowane okno suma kontrolna wskaźnik pilnych danych dodatkowe opcje, np. potwierdzanie selektywne "7
Dzisiaj Programowanie gniazd TCP Implementacja TCP "8
Programowanie gniazd
Interfejs programistyczny warstwa aplikacji Aplikacja korzystąca z TCP Aplikacja korzystąca z UDP interfejs gniazd strumieniowych warstwa transportowa interfejs gniazd datagramowych TCP UDP ICMP warstwa sieciowa IP interfejs gniazd surowych Interfejs programistyczny BSD sockets Przystępne wprowadzenie: Beej's Guide to Network Programming. "10
Komunikacja Komunikacja bezpołączeniowa Strony nie utrzymują stanu. Przykładowo: zwykła poczta. Komunikacja połączeniowa Na początku strony wymieniają komunikaty nawiązujące połączenie. Późniejsza komunikacja wygodniejsza niż w przypadku bezpołączeniowym. Na końcu trzeba zakończyć połączenie. Przykładowo: telefon. "11
Gniazda UDP Gniazdo jest związane z konkretnym procesem. Gniazdo identyfikowane przez lokalny adres IP + lokalny port. Gniazdo nie posiada stanu. Gniazdo nie jest połączone z innym gniazdem. Nie ma różnicy między klientem i serwerem: po pierwszym wywołaniu sendto() gniazdo klienta otrzymuje od jądra numer portu i zachowuje się identycznie jak gniazdo serwera. "12
Gniazda TCP: dwa typy gniazd TCP: gniazda nasłuchujące Dla serwera, tylko do nawiązywania połączeń Tylko jedna strona gniazda (lokalna) ma przypisany adres: 172.16.16.14:80 *:* TCP: gniazda połączone Tworzone dla klienta i serwera po połączeniu, do wymiany właściwych danych. Gniazdo serwera: 172.16.16.14:80 22.33.44.55:44444 Gniazdo klienta: 22.33.44.55:44444 172.16.16.14:80 TCP: gniazdo opisywane przez cztery elementy: lokalny IP, lokalny port, zdalny IP, zdalny port. demonstracja "13
Dobrze znane porty Skąd wiemy, że powinniśmy się łączyć właśnie z portem 22? Dobrze znane porty (well known ports) Niektóre usługi mają porty zarezerwowane przez standardy: 22 - port SSH 80 - port HTTP 443 - port HTTPS /etc/services "14
Przykład klienta i serwera TCP tcp_server1.c + telnet tcp_server1.c + tcp_client1.c demonstracja cały kod serwera cały kod klienta "15
Implementacja TCP
Flagi w segmencie TCP 0 7 8 15 16 23 24 31 port źródłowy port docelowy numer sekwencyjny (numer pierwszego bajtu w segmencie) numer ostatniego potwierdzanego bajtu + 1 offset 000 ECN U-A-P-R-S-F oferowane okno suma kontrolna wskaźnik pilnych danych dodatkowe opcje, np. potwierdzanie selektywne Flagi = zapalone bity SYN = synchronize (do nawiązywania połączenia) ACK = pole numer potwierdzanego bajtu ma znaczenie FIN = finish (do kończenia połączenia) "17
Cykl życia połączenia Trójfazowe nawiązywanie połączenia Przesyłanie danych. Czterofazowe kończenie połączenia "18
Trójfazowe nawiązywanie połączenia (1) klient TCP serwer TCP CLOSED CLOSED socket(), bind(), listen() socket() SYN SENT connect() blokuje SYN 1, K AC ESTABLISHED connect() powraca accept() blokuje 0 SYN ACK SYN RECEIVED 0 1 accept() powraca "19 LISTEN ESTABLISHED
Trójfazowe nawiązywanie połączenia (2) Przejście do stanu LISTEN = otwarcie bierne (nie wysyła pakietu), wykonuje serwer TCP. Przejście do stanu SYN_SENT = otwarcie czynne (wysyła segment SYN), wykonuje klient TCP. W rzeczywistości w segmencie SYN nie jest wysyłany numer 0, tylko początkowy numer sekwencyjny: losowy, trudny do zgadnięcia zapobiega podszywaniu się! łatwo sfałszować źródłowy adres IP, ale trudno z takiego adresu rozpocząć komunikację TCP. "20
Przesyłanie danych ESTABLISHED ESTABLISHED send() dane dane dane recv() ACK recv() odczytuje dane (lub ich część) z gniazda. ACK Blokuje, jeśli gniazdo puste. "21
Czterofazowe kończenie połączenia (1) ESTABLISHED FIN WAIT 1 ESTABLISHED close() FIN M M+1 K C A CLOSE WAIT Od tej pory wywołania recv() zwrócą 0. FIN WAIT 2 "22
Czterofazowe kończenie połączenia (2) ESTABLISHED FIN WAIT 1 ESTABLISHED close() FIN M CLOSE WAIT M+1 K C A FIN WAIT 2 TIME WAIT N FIN close() LAST ACK ACK N +1 ~ 1 min. CLOSED CLOSED demonstracja "23
Po co jest stan TIME WAIT? FIN WAIT 2 N FIN TIME WAIT close() LAST ACK ACK N +1 ~ 1 min. CLOSED wie, że połączenie zostało zakończone CLOSED Lewa strona nie wie, czy prawa strona dostała jej ACK Końcowy ACK nie dociera prawa strona wysyła FIN jeszcze raz lewa strona chce go poprawnie obsłużyć. Dodatkowy cel: nie chcemy żeby ktoś szybko utworzył połączenie TCP o takich samych parametrach (IP + porty) stare duplikaty segmentów mogłyby być uznane za należące do nowego połączenia. "24
Stany TCP: sytuacje nietypowe Obrazek ze strony https://en.wikipedia.org/wiki/transmission_control_protocol "25
Segment RST Segment z flagą RST (reset): wysyłany kiedy wystąpi błąd. Przykładowo w odpowiedzi na dowolny segment wysłany do zamkniętego portu. Po otrzymaniu takiego segmentu z gniazda nie można już korzystać. "26
Wysyłanie większych danych
Funkcja send() Czy nasz klient działa poprawnie? Wyślijmy 1, 2, 3,... mln bajtów "28
Funkcja send() Czy nasz klient działa poprawnie? Wyślijmy 1, 2, 3,... mln bajtów send() może wysłać mniej i to nie jest błąd! "28
Funkcja send() Czy nasz klient działa poprawnie? Wyślijmy 1, 2, 3,... mln bajtów send() może wysłać mniej i to nie jest błąd! send() zapisuje dane tylko do bufora wysyłkowego, zakończenie tej funkcji nie oznacza faktycznego wysłania. "28
Funkcja recv() Nowa wersja klienta server1.c + client2.c Wyślijmy 1, 2, 3,... mln bajtów. Klient zostaje zabity przez SIGPIPE?! cały kod nowego klienta "29
Dlaczego SIGPIPE? "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) serwer: wysyła odpowiedź i zamyka połączenie. "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) serwer: wysyła odpowiedź i zamyka połączenie. klient: send() wysyła kolejny segment. "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) serwer: wysyła odpowiedź i zamyka połączenie. klient: send() wysyła kolejny segment. TCP po stronie serwera odpowiada segmentem RST. "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) serwer: wysyła odpowiedź i zamyka połączenie. klient: send() wysyła kolejny segment. TCP po stronie serwera odpowiada segmentem RST. TCP po stronie klienta zamyka gniazdo. "30
Dlaczego SIGPIPE? klient: send() zapisuje część lub całość do bufora wysyłkowego. TCP po stronie klienta wysyła kilka segmentów (np. po 16 KB). TCP po stronie serwera potwierdza segmenty (część lub wszystkie) serwer: recv() odczytuje pewien fragment bufora odbiorczego (np. 32 KB) serwer: wysyła odpowiedź i zamyka połączenie. klient: send() wysyła kolejny segment. TCP po stronie serwera odpowiada segmentem RST. TCP po stronie klienta zamyka gniazdo. klient: send() wysyła kolejny segment (przez zamknięte gniazdo!) otrzymuje sygnał SIGPIPE. "30
Na czym polega problem? Do jakiego momentu recv() powinno czytać dane? Problem: nie zdefiniowaliśmy protokołu komunikacji! Podejście nr 1: ustalamy znacznik końca rekordu (np. koniec wiersza) i czytamy do tego znacznika. Podejście nr 2: na początku wysyłamy rozmiar danych. "31
Tryb nieblokujący Funkcja recv(): Standardowe wywołanie blokuje aż w gnieździe będą jakiekolwiek dane. Może być tylko jeden bajt! Zazwyczaj nie chcemy czekać więcej niż x sekund. Tryb nieblokujący: Czwarty parametr recv() równy MSG_DONTWAIT. Jeśli w gnieździe nie ma pakietów, to recv() kończy działanie zwracając -1 zaś errno = EWOULDBLOCK. "32
Tryb nieblokujący Funkcja recv(): Standardowe wywołanie blokuje aż w gnieździe będą jakiekolwiek dane. Może być tylko jeden bajt! Zazwyczaj nie chcemy czekać więcej niż x sekund. Tryb nieblokujący: Czwarty parametr recv() równy MSG_DONTWAIT. Jeśli w gnieździe nie ma pakietów, to recv() kończy działanie zwracając -1 zaś errno = EWOULDBLOCK. Aktywne czekanie: Wywołujemy w pętli cały czas recv(sockfd,_,_,msg_dontwait). Sprawdzamy, ile czasu upłynęło od ostatniego odczytu. Wada: 100% zużycie procesora! "32
Przypomnienie: funkcja select() Czekanie maksymalnie x sekund na dane w gnieździe sockfd. fd_set descriptors; FD_ZERO (&descriptors); FD_SET (sockfd, &descriptors); struct timeval tv; tv.tv_sec = x; tv.tv_usec = 0; int ready = select (sockfd+1, &descriptors, NULL, NULL, &tv); ready < 0 wystąpił błąd. ready = 0 nastąpił timeout (po x sekundach). ready > 0 ready obserwowanych deskryptorów gotowych do odczytu. Pierwsze wywołanie recv(sockfd, ) nie zablokuje. W gnieździe sockfd może być więcej danych można je odczytać w trybie nieblokującym. "33 cały kod nowego serwera
Lektura dodatkowa Kurose, Ross: rozdział 3 Tanenbaum: rozdział 6 Stevens: rozdziały 3-6, 13, 27 Beej's Guide to Network Programmin: https://beej.us/guide/bgnet/ "34