Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Poprzednia wersja Nowa wersja | Poprzednia wersja | ||
sk2:sockets_intro [2020/10/27 10:56] jkonczak [C++] |
sk2:sockets_intro [2024/10/07 20:27] (aktualna) jkonczak |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
====== Wstęp – przypomnienia ====== | ====== Wstęp – przypomnienia ====== | ||
+ | |||
+ | \\ | ||
==== C++ ==== | ==== C++ ==== | ||
- | Większość przykładów w materiałach i programów pisanych na laboratoriach jest w C++.\\ | + | Większość przykładów w materiałach i programów pisanych na laboratoriach jest w C+////+.\\ |
Stąd przypominam jak obsługiwać kompilator GCC / clang w Linuksie. | Stąd przypominam jak obsługiwać kompilator GCC / clang w Linuksie. | ||
Przykładowe polecenie do kompilacji przykładów ze strony: | Przykładowe polecenie do kompilacji przykładów ze strony: | ||
- | ''g+////+ --std=c+////+17 -Wall -O0 -g -pthread -o example example.cpp'' | + | <html><code>g++ --std=c++20 -Wall -O0 -g <html><span style="color:gray;">-pthread</span> -o example example.cpp</code></html> |
|''c+////+''|domyślny kompilator C+////+. Zwykle link do ''g+////+'' lub ''clang+////+''| | |''c+////+''|domyślny kompilator C+////+. Zwykle link do ''g+////+'' lub ''clang+////+''| | ||
|''c+////+ zrodlo.cpp -o prog''|kompiluje plik ''zrodlo.cpp'' do programu ''prog''| | |''c+////+ zrodlo.cpp -o prog''|kompiluje plik ''zrodlo.cpp'' do programu ''prog''| | ||
- | |''c+////+ -Wall z.cpp -o p''|włącza wszystkie ostrzeżenia kompilatora (''-W'' = warn, ''all'' = wszystkie)| | + | |''c+////+ -Wall z.cpp -o p''|włącza wszystkie(("Wszystkie" oznacza wybrany zbiór ostrzeżeń o nazwie wszystkie, poza ''-Wall'' warto też dodać ''-Wextra'' i rozważyć dodanie ''-pedantic''. Szczegóły w dokumentacji kompilatora [[https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html|gcc]]/[[https://clang.llvm.org/docs/UsersManual.html#enabling-all-diagnostics|clang]])) ostrzeżenia kompilatora (''-W'' = warn, ''all'' = wszystkie)| |
|''c+////+ -O0 -g z.cpp -o p''|wyłącza optymalizacje i dodaje do programu dane umożliwiające debugowanie| | |''c+////+ -O0 -g z.cpp -o p''|wyłącza optymalizacje i dodaje do programu dane umożliwiające debugowanie| | ||
- | |''c+////+ --std=c+////+17 z.cpp -o p''|włącza używanie standardu ISO C+////+ z 2017 roku| | + | |''c+////+ --std=c+////+20 z.cpp -o p''|włącza używanie standardu ISO C+////+ z 2020 roku| |
- | |''c+////+ -pthread z.cpp -o p''|włącza obsługę wątków standardu POSIX| | + | |<html><code><span style="color:gray;">c++ -pthread z.cpp -o p</span></code></html>|<html><span style="color:gray;"></html>włącza obsługę wątków standardu POSIX \\ wymagane do wersji glibc ≤ 2.33 [[https://developers.redhat.com/articles/2021/12/17/why-glibc-234-removed-libpthread|[1]]] [[https://lists.gnu.org/archive/html/info-gnu/2021-08/msg00001.html|[2]]]<html></span></html>| |
- | <html><!--<small></html>W przykładach nie pojawiają się nowości z obowiązującego C+////+17 i przyszłego C+////+20, co nie znaczy że macie się ograniczać do C+////+11.<html></small>--></html> | + | |
Przykładowy plik cmake: | Przykładowy plik cmake: | ||
<file cmake CMakeLists.txt> | <file cmake CMakeLists.txt> | ||
- | cmake_minimum_required(VERSION 3.1) | + | cmake_minimum_required(VERSION 3.12) |
project(projname) | project(projname) | ||
if(NOT CMAKE_BUILD_TYPE) | if(NOT CMAKE_BUILD_TYPE) | ||
set(CMAKE_BUILD_TYPE "Debug") | set(CMAKE_BUILD_TYPE "Debug") | ||
endif() | endif() | ||
- | set(CMAKE_CXX_STANDARD 17) | + | set(CMAKE_CXX_STANDARD 20) |
find_package(Threads) | find_package(Threads) | ||
- | link_libraries(${CMAKE_THREAD_LIBS_INIT}) | + | link_libraries(Threads::Threads) |
add_executable(example1 example1.cpp) | add_executable(example1 example1.cpp) | ||
add_executable(example2 example2.cpp) | add_executable(example2 example2.cpp) | ||
- | # target_link_libraries(example2 ${CMAKE_THREAD_LIBS_INIT}) | + | # target_link_libraries(example2 Threads::Threads) |
</file> | </file> | ||
==== Obsługa plików w POSIX ==== | ==== Obsługa plików w POSIX ==== | ||
Interface obsługi gniazd BSD jest bardzo zbliżony do API specyfikowanego przez POSIX do obsługi plików (który znacie z PSiW). \\ <html><small> BSD socket API został przyjęty jako standard przez większość systemów operacyjnych, m. inn. został bez większych zmian wpisany w standard POSIX.</small></html> | Interface obsługi gniazd BSD jest bardzo zbliżony do API specyfikowanego przez POSIX do obsługi plików (który znacie z PSiW). \\ <html><small> BSD socket API został przyjęty jako standard przez większość systemów operacyjnych, m. inn. został bez większych zmian wpisany w standard POSIX.</small></html> | ||
- | //Zadanie 1.// Napisz program który otworzy plik o nazwie 'date' i wypisze jego zawartość. Poniżej "pusty" plik źródłowy. Pomiń obsługę błędów. (Jeśli nie wiesz skąd wziąć plik ''date'', wpisz w konsolę: ''date>date'' .) \\ Do obsługi pliku i standardowego wejścia / wyjścia użyj funkcji ''open'', ''read'', ''write'' i ''close''. \\ | + | ~~Zadanie.#~~ Napisz program który otworzy plik o nazwie 'date' i wypisze jego zawartość. Poniżej "pusty" plik źródłowy. Pomiń obsługę błędów. (Jeśli nie wiesz skąd wziąć plik ''date'', wpisz w konsolę: ''date>date'' .) \\ Do obsługi pliku i standardowego wejścia / wyjścia użyj funkcji ''open'', ''read'', ''write'' i ''close''. \\ |
Opis funkcji znajdziesz na stronach podręcznika systemowego (np. ''man open''). | Opis funkcji znajdziesz na stronach podręcznika systemowego (np. ''man open''). | ||
<file cpp z1.cpp> | <file cpp z1.cpp> | ||
Linia 46: | Linia 47: | ||
</file> | </file> | ||
- | //Zadanie 2.// Co trzeba dodać do obsłużenia błędów? | + | ~~Zadanie.#~~ Co trzeba dodać do obsłużenia błędów? |
==== Adresacja połączeń na warstwie transportu ==== | ==== Adresacja połączeń na warstwie transportu ==== | ||
- | //Zadanie 3.// Jakie adresy (numery) są potrzebne by móc przesłać wiadomość do konkretnego programu na wybranym komputerze? | + | ~~Zadanie.#~~ Jakie adresy (numery) są potrzebne by móc przesłać wiadomość do konkretnego programu na wybranym komputerze? |
Przypomnienie programów ''netcat'' / ''socat'' oraz programów ''netstat'' / ''ss'' ([[sk1:transport#monitorowanie_biezacych_polaczen|link do materiałów z SK1]]) | Przypomnienie programów ''netcat'' / ''socat'' oraz programów ''netstat'' / ''ss'' ([[sk1:transport#monitorowanie_biezacych_polaczen|link do materiałów z SK1]]) | ||
- | //Zadanie 4.// Prześlij między sobą dowolny tekst używając programu ''netcat'' lub ''socat'' | + | ~~Zadanie.#~~ Prześlij między sobą dowolny tekst używając programu ''netcat'' lub ''socat'' |
- | //Zadanie 5.// Nawiąż połączenie na port 13 (daytime) twojego komputera. | + | ~~Zadanie.#~~ Nawiąż połączenie na port 13 (daytime) twojego komputera. \\ |
+ | <html><small></html>Jeżeli używasz własnego komputera i port 13 nie odpowiada, uruchom i pozostaw działającą w osobnym terminalu komendę \\ ''socat tcp-listen:1313,fork,reuseaddr exec:date'' i do tego oraz dalszych ćwiczeń używaj port 1313.<html></small></html> | ||
<html><small></html>Więcej informacji o "useful debugging and measurement tools": | <html><small></html>Więcej informacji o "useful debugging and measurement tools": | ||
Linia 82: | Linia 84: | ||
Przykład wysłania liczby 0x010F, czyli 271, czyli 0b0000000100001111 | Przykład wysłania liczby 0x010F, czyli 271, czyli 0b0000000100001111 | ||
|byte order\bit order|MSB first|LSB first| | | | |byte order\bit order|MSB first|LSB first| | | | ||
- | |little endian|0000111100000001|1111000010000000| x86 |<html><div style="margin-top:1em">ARM, IA-64 (Itanium), SPARC≥v9</div></html>| | + | |little endian|0000111100000001|1111000010000000| x86/x86_64 |<html><div style="margin-top:1em">ARM, IA-64 (Itanium), SPARC≥v9, RISC-V</div></html>| |
|big endian|0000000100001111|1000000011110000|Motorola 68k, SPARC<v9, z/Arch| :::| | |big endian|0000000100001111|1000000011110000|Motorola 68k, SPARC<v9, z/Arch| :::| | ||
| | I²C, SDH | Ethernet, RS232, USB | | | | | I²C, SDH | Ethernet, RS232, USB | | | ||
Linia 96: | Linia 98: | ||
uint16_t networkEndianessPort = htons(hostEndianessPort); | uint16_t networkEndianessPort = htons(hostEndianessPort); | ||
</code> | </code> | ||
- | Opis funkcji pomocniczych: [[http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#funkcje-pomocnicze]] | + | Opis funkcji pomocniczych – patrz ''man byteorder'' lub [[http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#funkcje-pomocnicze|strona Darka Dwornikowskiego]] |
==== Zapis adresu gniazda ==== | ==== Zapis adresu gniazda ==== | ||
Linia 106: | Linia 108: | ||
Ta struktura nie pozwala na bezpośrednie wykorzystanie. Zamiast tego dla IPv4 należy używać **''sockaddr_in''** (w C – ''struct sockaddr_in'') | Ta struktura nie pozwala na bezpośrednie wykorzystanie. Zamiast tego dla IPv4 należy używać **''sockaddr_in''** (w C – ''struct sockaddr_in'') | ||
- | Opis struktury: ''man 7 ip'' lub ''man netinet_in.h'' lub | + | Opis struktury – patrz ''man 7 ip'' i ''man netinet_in.h'' lub |
- | [[http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#glowne-funkcje-interfejsu-gniazd]] | + | [[http://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#glowne-funkcje-interfejsu-gniazd|strona Darka]] |
<html><small></html> | <html><small></html> | ||
Linia 118: | Linia 120: | ||
==== "Hello world" ==== | ==== "Hello world" ==== | ||
- | //Zadanie 6.// Zmień program do odczytu pliku tak, by zamiast funkcji ''open(…)'': | + | ~~Zadanie.#~~ Zmień program do odczytu pliku tak, by zamiast funkcji ''open(…)'': |
* tworzył funkcją ''socket(…)'' gniazdo: | * tworzył funkcją ''socket(…)'' gniazdo: | ||
* domeny komunikacyjnej protokołu IPv4 – stała ''PF_INET'' (zamiennie ''AF_INET'') | * domeny komunikacyjnej protokołu IPv4 – stała ''PF_INET'' (zamiennie ''AF_INET'') | ||
Linia 126: | Linia 128: | ||
* rodzina adresów IPv4 – stała ''AF_INET'' | * rodzina adresów IPv4 – stała ''AF_INET'' | ||
* port – 13 (port usługi daytime; pamiętaj o porządku bajtów - ''htons'') | * port – 13 (port usługi daytime; pamiętaj o porządku bajtów - ''htons'') | ||
- | * adres IP – 127.0.0.1 (localhost, do konwersji użyj ''inet_addr'' lub ''inet_aton''); \\ można też ustawić adres na stałą ''htonl(INADDR_LOOPBACK)''. \\ <html><small></html> Uwaga: ''.sin_addr'' to struktura typu ''in_addr'' z jedną składową ''.s_addr'' typu ''uint32_t'' \\ ''inet_addr'' przyjmuje wskaźnik na strukturę, natomiast ''inet_aton'' zwraca liczbę którą trzeba przypisać składowej ''.s_addr'': \\ <code cpp>sockaddr_in nazwa_zmiennej; | + | * adres IP – 127.0.0.1 (localhost, do konwersji użyj ''inet_addr'' lub ''inet_aton''); \\ można też ustawić adres na stałą ''htonl(INADDR_LOOPBACK)''. \\ <html><small></html> Uwaga: ''.sin_addr'' to struktura typu ''in_addr'' z jedną składową ''.s_addr'' typu ''uint32_t'' \\ ''inet_aton'' przyjmuje wskaźnik na strukturę, natomiast ''inet_addr'' zwraca liczbę którą trzeba przypisać składowej ''.s_addr'': \\ <code cpp>sockaddr_in nazwa_zmiennej; |
wersja 1: nazwa_zmiennej.sin_addr.s_addr = inet_addr("8.8.8.8"); | wersja 1: nazwa_zmiennej.sin_addr.s_addr = inet_addr("8.8.8.8"); | ||
wersja 2: inet_aton("8.8.8.8", &nazwa_zmiennej.sin_addr); | wersja 2: inet_aton("8.8.8.8", &nazwa_zmiennej.sin_addr); | ||
Linia 134: | Linia 136: | ||
* trzeci argument funkcji connect to rozmiar struktury opisującej adres – ''sizeof()'' zmiennej lub typu | * trzeci argument funkcji connect to rozmiar struktury opisującej adres – ''sizeof()'' zmiennej lub typu | ||
* przed wywołaniem funkcji ''close()'' zamykał połączenie funkcją ''shutdown()''; \\ <html><small></html>w funkcji ''shutdown()'' można osobno zakończyć nadawanie i odbiór, drugi argument określa co zakończyć – ''SHUT_RD'' / ''SHUT_WR'' / ''SHUT_RDWR''<html></small></html> | * przed wywołaniem funkcji ''close()'' zamykał połączenie funkcją ''shutdown()''; \\ <html><small></html>w funkcji ''shutdown()'' można osobno zakończyć nadawanie i odbiór, drugi argument określa co zakończyć – ''SHUT_RD'' / ''SHUT_WR'' / ''SHUT_RDWR''<html></small></html> | ||
- | Opis funkcji – strona Darka lub ''man 3 …'' / ''man 3p …''\\ | + | Opis funkcji – [[https://www.cs.put.poznan.pl/ddwornikowski/sieci/sieci2/bsdsockets.html#glowne-funkcje-interfejsu-gniazd|strona Darka]] lub ''man 3 …'' / ''man 3p …''\\ |
Potrzebne pliki nagłówkowe to: | Potrzebne pliki nagłówkowe to: | ||
<code cpp> | <code cpp> | ||
Linia 142: | Linia 144: | ||
</code> | </code> | ||
- | //Zadanie 7.// Przekształć poprzedni program tak, by czytał z adresu IP i portu podanego w argumentach programu. | + | ~~Zadanie.#~~ Przekształć poprzedni program tak, by czytał z adresu IP i portu podanego w argumentach programu. |
- | //Zadanie 8.// Dodaj do programu obsługę błędów zwracanych przez funkcje ''connect'' i ''read''. | + | ~~Zadanie.#~~ Dodaj do programu obsługę błędów zwracanych przez funkcje ''connect'' i ''read''. |
+ | ~~Zadanie.#~~ Zmień IP na losowe (tak, by nie odpowiadało na próbę połączenia). Programem ''netstat -tnp'' / ''ss -tnp'' wyświetl utworzone połączenie. | ||
- | //Zadanie 9.// Zmień IP na losowe (tak, by nie odpowiadało na próbę połączenia). Programem ''netstat -tnp'' / ''ss -tnp'' wyświetl utworzone połączenie. | + | ==== Funkcje send/recv/… ==== |
- | <html><small></html> | + | Poza funkcją ''read(…)'' do odbierania danych można używać funkcji ''recv'', |
- | //Zadanie 10.// Zmień program tak, by zamiast ''read(…)'' używał funkcji ''recv(…)'' | + | <small> ''recvfrom'' i ''recvmsg''</small>, przy czym ''read(fd, buf, len)'' jest |
+ | równoważne ''recv(fd, buf, len, 0)'' i ''recvfrom(sockfd, buf, len, 0, NULL, NULL)''. \\ | ||
+ | Podobnie poza funkcją ''write'' do wysyłania można używać też funkcji ''send'', | ||
+ | <small>''sendto'' i ''sendmsg''</small>, analogicznych do powyższych. \\ | ||
+ | Dodatkowy argument ''recv''/''send'' (pole flag) pozwala na zmianę zachowania | ||
+ | tych funkcji i będzie omawiany później.\\ | ||
+ | <small> | ||
+ | ''recvfrom'' i ''sendto'' mają dodatkowe pole na adres nadawcy/odbiorcy i są | ||
+ | przeznaczone dla protokołów warstwy transportowej pozwalających na komunikację | ||
+ | po jednym gnieździe z wieloma partnerami. Będą omawiane przy obsłudze UDP. | ||
+ | </small> | ||
- | //Zadanie 11.// Przed wywołaniem ''connect'' ustal lokalny adres funkcją ''bind''. Powtórz zadanie 8. | + | ~~Zadanie.#~~ Zmień program tak, by zamiast ''read(…)'' używał funkcji ''recv(…)'' |
- | <html></small></html> | + | |
+ | <small> | ||
+ | ~~Zadanie.#~~ Przed wywołaniem ''connect'' ustal lokalny adres funkcją ''bind''. Powtórz zadanie 8 i 9. | ||
+ | </small> |