Dydaktyka:
FeedbackTo jest stara wersja strony!
Schemat kolejności wywołać funkcji bibliotecznych znajduje się na:
http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#rys-1
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(…)
używa się 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:
bind
),listen
),listen
jako drugi argument przyjmuje ile nowych połączeń może naraz czekać na odebranie funkcją acceptaccept
); na razie drugi i trzeci argument funkcji accept
ustaw na 0
lub nullptr
,
Zadanie 2a: Krótko1) po zamknięciu programu serwera sprawdź poleceniem netstat -tpn
w jakim stanie jest połączenie. Przypomnij sobie co oznacza ten stan - RFC793. Spróbuj w tym czasie uruchomić ponownie program serwera.
Zadanie 2b: Ustaw przed wywołaniem bind
opcję SO_REUSEADDR
gniazda (kod poniżej) i powtórz zadanie 2a.
const int one = 1; setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
Zadanie 3: Zakomentuj wywołanie bind, uruchom program i odczytaj z wyników komendy netstat -tlpn
na jakim porcie nasłuchuje twój serwer. Następnie połącz się do niego.
Zadanie 4: 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 jej podać:
accept
na wpisany rozmiar przekazanej struktury
Jeśli drugi i trzeci argument są niezerowe, accept
wypisuje przekazaną strukturę (drugi argument) i ustawia ile bajtów przekazanej struktury wypełnił (trzeci argument).
Zadanie 5: Dodaj do programu wyświetlanie z jakiego adresu IP i numeru portu nawiązano połączenie
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:
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) // lub: socket(PF_INET, SOCK_DGRAM, 0)
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
.
Przykład użycia funkcji sendto
i recvfrom
:
sockaddr_in nazwa_zmiennej {...}; socklen_t inna_zmienna = sizeof(nazwa_zmiennej); kolejna_zmienna = sendto(sockfd, "wiadomosc", 9, 0, (sockaddr*) &nazwa_zmiennej, inna_zmienna); kolejna_zmienna = recvfrom(sockfd, bufor, rozmiar_bufora, 0, (sockaddr*) &nazwa_zmiennej, &inna_zmienna);
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 6. Odpowiedz na pytanie dlaczego DNS używa UDP zamiast TCP do zapytań.
Zadanie 7. Napisz program, który korzystając z protokołu UDP wyśle dane (stały ciąg znaków) pod wskazany adres, następnie odbierze dane i się zakończy.
Zadanie 8. Napisz program, który korzystając z protokołu UDP odbierze dane i odeśle je pod adres nadawcy zmieniając wielkość liter.
Jeśli nie wiesz jak zmienić wielkość liter, to for(char *it=str; (*it=toupper(*it)); ++it);
Zadanie 9. Napisz program, który będzie w pętli odbierać dane i odsyłać je pod adresy wszystkich wcześniejszych nadawców.