przejście do zawartości
Jan Kończak
Narzędzia użytkownika
Zaloguj
Narzędzia witryny
Narzędzia
Pokaż stronę
Poprzednie wersje
Odnośniki
Ostatnie zmiany
Menadżer multimediów
Indeks
Zaloguj
Ostatnie zmiany
Menadżer multimediów
Indeks
Jesteś tutaj:
start
»
sk2
»
sockets_full
sk2:sockets_full
Ta strona jest tylko do odczytu. Możesz wyświetlić źródła tej strony ale nie możesz ich zmienić.
====== Interface gniazd BSD ====== Schemat kolejności wywołać funkcji bibliotecznych znajduje się na: \\ [[http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#rys-1]] ===== Serwer TCP ===== Aby oczekiwać na przychodzące połączenia TCP, po stworzeniu gniazda (''socket(…)'') wystarczy wywołać funkcję ''listen(…)'', ale: jeśli wcześniej nie ustawi się adresu gniazda, system operacyjny wylosuje efemeryczny port i rozpocznie nasłuch na dowolnym adresie IP na tym porcie.\\ Dlatego przed funkcją ''listen(…)'' należy użyć funkcji ''bind(…)'' do ustawienia lokalnego adresu gniazda. Funkcja ''bind'' przyjmuje jako argument strukturę ''sockaddr''. Lokalny adres IP można ustawić na dowolny – ''INADDR_ANY'' lub wybrany przez siebie – np. 127.0.0.1 (''INADDR_LOOPBACK'') jeśli połączenia mają być ograniczone do localhosta. Po wywołaniu funkcji ''listen'' system operacyjny system operacyjny czeka na połączenia. Do odebrania nowego połączenia należy użyć funkcji ''accept(…)''. Funkcja accept zwróci nowe gniazdo reprezentujące nawiązane połączenie. //Zadanie 1:// Napisz program, który: * stworzy gniazdo, * ustali adres (''bind''), * rozpocznie oczekiwanie na połączenia (''listen''), * zaakceptuje połączenie (''accept''); na razie drugi i trzeci argument funkcji ''accept'' pozostaw pusty, * wyśle tam dane (stały ciąg znaków), * zakończy program. //Zadanie 2:// Zmodyfikuj program tak, by w pętli obsługiwał nowe połączenia Funkcja ''accept'' (podobnie jak wprowadzana za chwilę ''recvfrom'') może przekazać informację o adresie z którego nawiązano połączenie. W tym celu należy podać jej adres struktury sockaddr (drugi argument) i adres zmiennej, która w momencie wywołania ''accept'' na wppisany rozmiar przekazanej struktury, a do której ''accept'' zapisze ile bajtów przekazanej struktury wypełnił (trzeci argument). //Zadanie 3:// Dodaj do programu wyświetlanie z jakiego adreesu IP i numeru portu nawiązano połączenie ===== UDP vs TCP - przypomnienie ==== TCP: Strumieniowy. Połączeniowy. Kontrola przepływu. Niezawodny (reliable). \\ UDP: Zorientowany na wiadomość. Bezpołączeniowy, bezstanowy. Brak kontroli przepływu. Best-effort. Tworząc gniazdo UDP należy użyć następujących argumentów: <code cpp> socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) // lub: socket(PF_INET, SOCK_DGRAM, 0) </code> UDP nie nawiązuje połączenia – do odbioru i wysyłania wiadomości należy używać funkcji ''sendto'' i ''recvfrom'' (lub ''recv''/''read'', jeśli nie obchodzi nas nadawca). W formie ułatwienia BSD socket API pozwala działać gniazdom UDP w trybie pseudo-połączeniowym - tzn. można wywołać funkcję ''connect'' (która ustali adres odbiorcy) i dalej korzystać z ''send'' / ''write''. UDP jest zorientowane na wiadomość – wysyła i odbiera całe datagramy. Jeśli funkcja odbierająca dane zadeklaruje mniejszy bufor niż rozmiar wiadomości, nadmiarowe dane zostaną odrzucone. //Zadanie 4.// Odpowiedz na pytanie dlaczego DNS używa UDP zamiast TCP do zapytań. ===== Klient UDP ===== //Zadanie 5.// Napisz program, który wyśle dane (stały ciąg znaków) pod wskazany adres, następnie odbierze dane i się zakończy. ===== Serwer UDP ===== //Zadanie 6.// Napisz program, który odbierze dane i odeśle je pod adres nadawcy zmieniając wielkość liter.\\ <html><small></html>Jeśli nie wiesz jak zmienić wielkość liter, to ''for(char *it=str; (*it=toupper(*it)); ++it);''<html></small></html> //Zadanie 7.// Napisz program, który będzie w pętli odbierać dane i odsyłać je pod adresy wszystkich wcześniejszych nadawców. ===== Read i Write - ilość odczytanych / zapisanych danych ===== Polecenie ''read'', ''recv'',… często zwracają mniej danych niż podana w argumentach wielkość bufora. Powód? Mniej danych przyszło lub skończyło się miejsce w buforze odbiorczym (''setsockopt(socket, SOL_SOCKET, SO_RCVBUF, …)''). Polecenia ''write'', ''send'',… może też zwrócić w pewnych okolicznościach mniejszy rozmiar wysłanych danych niż podany rozmiar buforu. Jest to spowodowane zapchaniem 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 ustawi się opcję ''O_NONBLOCK'' (typowa w wielu zastosowaniach), to funkcje takie jak ''write'', ''send'', … zapisują tylko część danych. Dlatego zarówno przy odbieraniu jak i wysyłaniu trzeba zwracać uwagę na zwracaną ilość przetworzonych danych. //Zadanie 8.// W serwerze TCP zmień rozmiar buforu nadawczego, przestaw gniazdo w tryb nieblokujący (kod poniżej) i każ wysłać ponad 4096 bajtów. Zaobserwuj co odbierze klient. __Uwaga:__ klient musi być z innego hosta. \\ <html><small></html>Nie wiesz jak wygenerować długi komunikat? ctrl+c, ctrl+v. Albo ''string s{"a"}; s.resize (22220,'='); s+="z";'' Potem: ''s.c_str()'' i ''s.length()''<html></small></html> <code cpp> int buffsize = 1024; setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)); fcntl(socket, F_SETFL, O_NONBLOCK, 1); </code> //Zadanie 9.// W kliencie UDP i TCP zmniejsz rozmiar bufora przekazywanego do funkcji odbioru wiadomości i wykonaj odbiór dwa razy. Zaobserwuj co odbierze klient. ===== Opcje gniazd ===== Strona podręcznika ''man 7 socket'' opisuje możliwe argumenty funkcji ''setsockopt'' i ''getsockopt''. Ważne opcje to: * ''SO_BROADCAST'' - wymagane do UDP broadcastu * ''SO_KEEPALIVE'' - włącza mechanizm TCP keepalive [[http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html]] * ''SO_LINGER'' – pozwala przed zamknięciem gniazda wysłać zakolejkowane dane * ''SO_RCVBUF'' i ''SO_SNDBUF'' – ustawienie rozmiaru systemowych buforów odbiorczych / nadawczych * ''SO_REUSEADDR'' – pomija stan TIME_WAIT po zamknięciu połączenia [[https://tools.ietf.org/html/rfc793#page-22]] 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''.)
sk2/sockets_full.1476894240.txt.gz
· ostatnio zmienione: 2016/10/19 18:24 przez
jkonczak
Narzędzia strony
Pokaż stronę
Poprzednie wersje
Odnośniki
Złóż / rozłóż wszystko
Do góry