Narzędzia użytkownika

Narzędzia witryny


sk2:sockets_caveats

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
sk2:sockets_caveats [2019/11/15 12:53]
jkonczak
sk2:sockets_caveats [2023/10/17 12:45] (aktualna)
jkonczak [Opcje gniazd]
Linia 6: Linia 6:
 **{{:​sk2:​l3.tar.xz|Kody źródłowe zadań 1-9,12}}** **{{:​sk2:​l3.tar.xz|Kody źródłowe zadań 1-9,12}}**
  
-<​html><​small></​html>​Aby zbudować programy ręcznie, wykonaj:<​code>​mkdir build+<​html><​small></​html>​ 
 +Uwaga: jeśli korzystasz z innej biblioteki niż glibc, ściągnij też plik {{:​sk2:​error.h|}} - w programach jest użyte niestandardowa funkcja [[https://​linux.die.net/​man/​3/​error|error]] z glibc, a podlinkowany plik jest uproszczoną implementacją tej funkcji. 
 + 
 +Aby ściągnąć i zbudować programy ręcznie, wykonaj:<​code>​wget -O - http://​www.cs.put.poznan.pl/​jkonczak/​_media/​sk2:​l3.tar.xz | tar xvJ 
 +cd l3 
 + 
 +mkdir build
 cd build cd build
 cmake .. cmake ..
Linia 17: Linia 23:
 ==== Read i Write - ilość odczytanych / zapisanych bajtów ​ ==== ==== Read i Write - ilość odczytanych / zapisanych bajtów ​ ====
  
-Funkcje ''​read'',​ ''​recv'',​… często zwracają mniej niż podana w argumentach wielkość bufora. Powód? Mniej danych przyszło lub skończyło się miejsce w buforze odbiorczym((Rozmiar bufora odbiorczego można ustawić funkcją: ''​setsockopt(socket,​ SOL_SOCKET, SO_RCVBUF, …)''​)). Może się tak stać nawet pomimo ustawienia flagi ''​MSG_WAITALL''​ w funkcji ''​recv''​ i podobnych (żądającej odebrania dokładnie tylu bajtów ile zażądano), np. w przypadku zakończenia połączenia.+Funkcje ''​read'',​ ''​recv'',​… często zwracają mniej niż podana w argumentach wielkość bufora. Powód? Mniej danych przyszło lub skończyło się miejsce w buforze odbiorczym((Rozmiar bufora odbiorczego można ustawić funkcją: ''​setsockopt(socket,​ SOL_SOCKET, SO_RCVBUF, …)''​)). Może się tak stać nawet pomimo ustawienia flagi ''​MSG_WAITALL''​ w funkcji ''​recv''​ i podobnych (żądającej odebrania dokładnie tylu bajtów ile podano), np. w przypadku zakończenia połączenia.
  
 Funkcje ''​write'',​ ''​send'',​… mogą też w pewnych okolicznościach wysłać mniejszą ilość bajtów niż zażądano. Funkcje ''​write'',​ ''​send'',​… mogą też w pewnych okolicznościach wysłać mniejszą ilość bajtów niż zażądano.
-Jest to spowodowane zapełnieniem systemowego buforu wysyłania (czyli jeśli dane są dostarczane do wysłania szybciej niż można je wysyłać). Normalnie funkcje zapisujące blokują się do momentu aż w buforze będzie dość miejsca. Jeśli jednak gniazdo pracuje w trybie nieblokującym (patrz niżej), to funkcje takie jak ''​write'',​ ''​send'',​ … zapiszą tylko część danych jeśli w buforze skończy się miejsce.+Jest to spowodowane zapełnieniem systemowego buforu wysyłania (czyli jeśli dane są dostarczane do wysłania szybciej niż można je wysyłać). Normalnie funkcje zapisujące blokują się do momentu aż w buforze będzie dość miejsca. Jeśli jednak gniazdo pracuje w trybie nieblokującym (patrz niżej), to funkcje takie jak ''​write'',​ ''​send'',​ … zapiszą tylko część danych jeśli w buforze ​systemowym ​skończy się miejsce.
  
 Dlatego zarówno przy odbieraniu jak i wysyłaniu trzeba sprawdzać zwracaną ilość przetworzonych danych. Dlatego zarówno przy odbieraniu jak i wysyłaniu trzeba sprawdzać zwracaną ilość przetworzonych danych.
Linia 26: Linia 32:
 ==== Funkcje blokujące / nieblokujące ===== ==== Funkcje blokujące / nieblokujące =====
  
-Zasadniczo funkcje które wymagają wysłania lub odebrania danych z sieci mogą się //​zablokować//,​ tj. po ich wywołaniu program zatrzymuje się do czasu zakończenia żądanej operacji. Przykłady ​takich ​funkcji to ''​read''​ / ''​recv''​ / ''​recvfrom''​ (czeka aż przyjdą dane)''​write''​ / ''​send''​ (czeka aż zwolni się miejsce w buforze nadawczym)''​connect''​ (czeka aż uda się nawiązać połączenie)''​accept''​ (czeka aż przyjdzie nowe połączenie)''​gethostbyname''​ / ''​getaddrinfo''​ (czeka na odpowiedź od serwera nazw, o ile zaszła konieczność odpytania).\\ +Zasadniczo funkcje które wymagają wysłania lub odebrania danych z sieci mogą się //​zablokować//,​ tj. po ich wywołaniu program zatrzymuje się do czasu zakończenia żądanej operacji ​(porz definicją [[https://​pubs.opengroup.org/​onlinepubs/​9699919799/​basedefs/​V1_chap03.html#​tag_03_77|blocking]] z POSIX). 
-Funkcje wykonujące tylko operacje lokalne są nieblokujące. Przykłady takich funkcji (sieciowych) to ''​socket'', ​ ''​bind'',​ ''​listen'',​ ''​setsockopt'',​ ''​gethostbyname''​ / ''​getaddrinfo''​ (o ile funkcja nie odpytywała serwera nazw).+\\ 
 +Przykłady funkcji ​które mogą się zablokować ​to
 +  * ''​read''​ / ''​recv''​ / ''​recvfrom''​ (czeka aż przyjdą dane) 
 +  * ''​write''​ / ''​send''​ (czeka aż zwolni się miejsce w buforze nadawczym) 
 +  * ''​connect''​ (czeka aż uda się nawiązać połączenie) 
 +  * ''​accept''​ (czeka aż przyjdzie nowe połączenie) 
 +  * ''​gethostbyname''​ / ''​getaddrinfo''​ (czeka na odpowiedź od serwera nazw, o ile zaszła konieczność odpytania). 
 +<​html><​div style="​margin-top:​-1.4em"></​html>​ 
 +Funkcje wykonujące tylko operacje lokalne są nieblokujące. 
 +\\ 
 +Przykłady takich funkcji (sieciowych) to''​socket'', ​ ''​bind'',​ ''​listen'',​ ''​setsockopt'',​ ''​gethostbyname''​ / ''​getaddrinfo''​ (o ile funkcja nie odpytywała serwera nazw). 
 +<​html></​div></​html>​
  
 Można zmienić domyśle blokujące zachowanie przestawiając gniazdo w //tryb nieblokujący//​. Można zmienić domyśle blokujące zachowanie przestawiając gniazdo w //tryb nieblokujący//​.
-Jeśli wykonanie żądanej funkcji na gnieździe w trybie nieblokującym nie jest możliwe bez czekania, to wykonanie funkcji nie powodzi się (zwracany jest wynik ''​-1''​) a zmienna ''​errno''​ jest ustawiana na ''​EAGAIN''​ lub ''​EWOULDBLOCK''​((Wyjątkiem jest funkcja ''​connect'',​ która rozpoczyna nawiązywanie połączenia w tle, zwraca ''​-1''​ i ustawia ''​errno''​ na ''​EINPROGRESS''​.)). Gniazdo przestawia się w tryb nieblokujący podobnie jak każdy inny deskryptor pliku:<​code cpp>​fcntl(fileDescriptor, F_SETFL, ​O_NONBLOCK1);</​code>​ +Jeśli wykonanie żądanej funkcji na gnieździe w trybie nieblokującym nie jest możliwe bez czekania, to wykonanie funkcji nie powodzi się (zwracany jest wynik ''​-1''​) a zmienna ''​errno''​ jest ustawiana na ''​EAGAIN''​ lub ''​EWOULDBLOCK''​((Wyjątkiem jest funkcja ''​connect'',​ która rozpoczyna nawiązywanie połączenia w tle, zwraca ''​-1''​ i ustawia ''​errno''​ na ''​EINPROGRESS''​.)). ​\\ Gniazdo przestawia się w tryb nieblokujący podobnie jak każdy inny deskryptor pliku: 
-Niektóre funkcje sieciowe (np. ''​recv'',​ ''​send''​) pozwalają na ustawienie w polu flag wartości ''​MSG_DONTWAIT'',​ która wykonuje żądaną operację w trybie nieblokującym niezależnie od tego w jakim trybie pracuje gniazdo:<​code cpp>​recv(fileDescriptor,​ buff, buffSize, MSG_DONTWAIT);</​code>​+<​html><​div style="​margin:​-1.4em 0 -1.4em 0"></​html>​ 
 +<code cpp>​fcntl(fd, F_SETFL, ​fcntl(fdF_GETFL) | O_NONBLOCK)</code
 +<​html></​div></​html
 +Niektóre funkcje sieciowe (np. ''​recv'',​ ''​send''​) pozwalają na ustawienie w polu flag wartości ''​MSG_DONTWAIT'',​ która wykonuje żądaną operację w trybie nieblokującym niezależnie od tego w jakim trybie pracuje gniazdo: 
 +<​html><​div style="​margin-top:​-1.4em"></​html>​ 
 +<code cpp>​recv(fileDescriptor,​ buff, buffSize, MSG_DONTWAIT);</​code>​ 
 +<​html></​div></​html>​ 
 +Uwaga: w BSD/POSIX socket API każde nowo utworzone gniazdo działa w trybie blokującym,​ nawet jeżeli gniazdo zostało utworzone w wyniku działania funkcji ''​accept''​ na nasłuchującym gnieździe działającym w trybie nieblokującym. ​  
  
 +<​small>​
 +W Linuksie można ustawiać tryb nieblokujący wykorzystując też niebędące częścią standardu POSIX rozszerzenia:​ 1) jeżeli ostatni argument funkcji ''​socket''​ będzie zsumowany z ''​SOCK_NONBLOCK'',​ to nowo stworzone gniazdo będzie w trybie nieblokującym (''​[[https://​man7.org/​linux/​man-pages/​man2/​socket.2.html|man 2 socket]]''​),​ 2) jeżeli zamiast funkcji ''​accept''​ wykorzysta się odpowiednik tej funkcji rozszerzony o pole flag – ''​accept4''​ – i poda flagę ''​SOCK_NONBLOCK''​ (''​[[https://​man7.org/​linux/​man-pages/​man2/​accept4.2.html|man 2 accept4]]''​)
 +</​small>​
 ==== Zadania ===== ==== Zadania =====
  
Linia 77: Linia 104:
 ===== Kolejność danych i (nie)zawodność ​ ===== ===== Kolejność danych i (nie)zawodność ​ =====
 //Zadanie 10.// Wykonaj z roota poniższe polecenie, które spowoduje pomieszanie kolejności pakietów wysłanych przez interfejs ''​lo'':​ //Zadanie 10.// Wykonaj z roota poniższe polecenie, które spowoduje pomieszanie kolejności pakietów wysłanych przez interfejs ''​lo'':​
 +<​html><​div style="​margin-top:​-1.4em"></​html>​
 <​code>​ <​code>​
 tc qdisc add dev lo root netem delay 5ms 5ms distribution normal loss 10% tc qdisc add dev lo root netem delay 5ms 5ms distribution normal loss 10%
 </​code>​ </​code>​
 +<​html></​div></​html>​
  
-Aby przywrócić domyślne zachowanie, ​wpisz:+Aby przywrócić domyślne zachowanie ​po wykonaniu ćwiczeńmożesz wpisać: 
 +<​html><​div style="​margin-top:​-1.4em"></​html>​
 <​code>​ <​code>​
 tc qdisc del root dev lo tc qdisc del root dev lo
 </​code>​ </​code>​
 +<​html></​div></​html>​
  
 //Zadanie 11.// Uruchom ponownie programy z zadań 5 i 7. //Zadanie 11.// Uruchom ponownie programy z zadań 5 i 7.
Linia 91: Linia 122:
  
 //Zadanie 13.// Wykonaj z roota poniższe polecenie, które spowoduje ograniczenie prędkości wysyłania pakietów i przetestuj program z poprzedniego zadania: //Zadanie 13.// Wykonaj z roota poniższe polecenie, które spowoduje ograniczenie prędkości wysyłania pakietów i przetestuj program z poprzedniego zadania:
 +<​html><​div style="​margin-top:​-1.4em"></​html>​
 <​code>​ <​code>​
 tc qdisc add dev lo root tbf rate 10kbps burst 1.5kb limit 10kb tc qdisc add dev lo root tbf rate 10kbps burst 1.5kb limit 10kb
 </​code>​ </​code>​
 +<​html></​div></​html>​
 +
 +<​html><​small></​html>​
 +
 +Dla TCP możesz zobaczyć gromadzone przez system operacyjny informacje używane do dobrania prędkości do możliwości łącza używając polecenia ''​ss''​ z przełącznikiem ''​i'',​ np: \\
 +''​ss -atip''​
 +
 +<​html></​small></​html>​
  
 //Zadanie 14.// Jak w protokole UDP radzić sobie z kolejnością pakietów? Jak radzić sobie ze zgubieniem pakietów? //Zadanie 14.// Jak w protokole UDP radzić sobie z kolejnością pakietów? Jak radzić sobie ze zgubieniem pakietów?
Linia 129: Linia 169:
 </​code>​++++ </​code>​++++
  
-Funkcja ''​fcntl''​ (''​man fcntl open''​) pozwala na ustawienie (''​F_SETFL''​) opcji ''​O_NONBLOCK''​ potrzebnej do nieblokującej obsługi gniazd. ​(''​O_NONBLOCK''​ można też ustawić sumując ostatni argument funkcji ''​socket''​ z ''​SOCK_NONBLOCK''​.)+Funkcja ''​fcntl''​ (''​man fcntl open''​) pozwala na ustawienie (''​F_SETFL''​) opcji ''​O_NONBLOCK''​ potrzebnej do nieblokującej obsługi gniazd.
  
sk2/sockets_caveats.1573818795.txt.gz · ostatnio zmienione: 2019/11/15 12:53 przez jkonczak