Both sides previous revision
Poprzednia wersja
Nowa wersja
|
Poprzednia wersja
|
pl:dydaktyka:unix:lab_prog_siec [2016/12/15 14:44] kkutt [DO PRZYGOTOWANIA] tekst o socketach |
pl:dydaktyka:unix:lab_prog_siec [2019/06/27 15:50] (aktualna) |
===== DO PRZYGOTOWANIA ===== | ===== DO PRZYGOTOWANIA ===== |
* Proszę przypomnieć sobie użycie ''[[http://home.agh.edu.pl/~gjn/dydaktyka/UGLX/node11.html#SECTION000117000000000000000|fork()]]'' | * Proszę przypomnieć sobie użycie ''[[http://home.agh.edu.pl/~gjn/dydaktyka/UGLX/node11.html#SECTION000117000000000000000|fork()]]'' |
* Proszę poczytać [[http://www.linuxpl.org/LPG/node81.html|opis podstaw gniazd sieciowych (socketów)]] | * Proszę poczytać opis podstaw gniazd sieciowych (socketów) z [[https://web.archive.org/web/20170405054449/http://www.linuxpl.org/LPG/node1.html|The Linux Programmer's Guide]]. Konkretnie sekcję [[https://web.archive.org/web/20170305021856/http://www.linuxpl.org:80/LPG/node81.html|Gniazda sieciowe - podstawy]] oraz jej podsekcje: "Podstawowe funkcje", "TCP: SOCK_STREAM", "SOCK_DGRAM (UDP)", "PF_UNIX", "SOCK_RAW i PF_PACKET" |
| |
===== WPROWADZENIE ===== | ===== WPROWADZENIE ===== |
* Funkcje konwersji: | * Funkcje konwersji: |
* //inet_pton// - konwertuje zapis "192.168.1.1" na odpowiednią strukturę - czyli inaczej konwertuje ''string'' do reprezentacji binarnej. | * //inet_pton// - konwertuje zapis "192.168.1.1" na odpowiednią strukturę - czyli inaczej konwertuje ''string'' do reprezentacji binarnej. |
* //inet_ntop// - konwertuje strukturę (reprezentację binarną) na ''string''. | * //inet_ntop// - konwertuje strukturę (reprezentację binarną) na ''string''. |
| |
==== Gniazda ==== | ==== Gniazda ==== |
* Gniazdo z ang. //socket//. | * Gniazdo z ang. //socket//. |
* Są używane na wyższej, czwartej warstwie sieciowego modelu OSI/ISO. | * Są używane w czwartej warstwie sieciowego modelu OSI/ISO. |
* Otwieranie ganiazd dokonuje się za pomocą funkcji //socket(int domain, int type, int protocol)//. | * Otwieranie gniazd (i uzyskanie deskryptora do komunikacji sieciowej) dokonuje się za pomocą funkcji <code c>socket(int domain, int type, int protocol)</code> |
* Proszę przeczytać manual funkcji (//man socket(3)//) | * Adres IP identyfikuje hosta w danej sieci (podsieci), co identyfikuje //numer portu//? |
* Adres IP identyfikuje hosta w danej sieci (podsieci), co identyfikuje //numer portu// | |
* Czym różni się deskryptor gniazda od deskryptora pliku? | * Czym różni się deskryptor gniazda od deskryptora pliku? |
* Odczytanie numeru portu na podstawie deskryptora dokonuje się za pomocą funkcji //bind(int sockfd, struct sockaddr *my_addr, int addrlen)//. | * Istnieje kilka rodzajów socketów w tym: |
* Przeczytać manual dla funkcji //bind(3)// zwrócić uwagę na parametry jakie przyjmuje i wartości jakie zwraca. | * //Stream Socket// - służą do komunikacji połączeniowej (użycie TCP) |
| * //datagram Socket// - służą do komunikacji bezpołączeniowej (użycie UDP) |
| * Powiązanie numeru portu z deskryptorem gniazda dokonuje się za pomocą funkcji <code c>bind(int sockfd, struct sockaddr *my_addr, int addrlen)</code> |
| * Proszę przeczytać manuale dla funkcji ''socket(2)'' i ''bind(2)'', zwrócić uwagę na parametry jakie przyjmują i wartości jakie zwracają. |
| |
==== Połączenie ==== | Podstawowe funkcje systemowe: {{ sockets-comm.png}} |
* Do nawiązywania połączeń wykorzystujemy funkcję //connect(int sockfd, struct sockaddr *serv_addr, int addrlen)// | * ''socket(2)'' |
* //sockfd// - deskryptor gniazda | * ''bind(2)'' |
* //serv_addr// - adres hosta docelowego, który możemy otrzymać przy pomocy funckji //getaddrinfo// | * ''listen(2)'' |
* //addrlen// - długość adresu, najczęściej podaje się wartość ''addrinfo::ai_addrlen'' | * ''accept(2)'' |
* Dopiero po pomyślnym nawiązaniu połączenia możemy używać //sockfd// do komunikowania się z serwerem. | * ''connect(2)'' |
| |
==== Nasłuchiwanie ==== | === Połączenie === |
* Rozpoczęcie nasłuchiwania nie wymaga użycia funkcji //connect// ponieważ to zdalny klient będzie jej używał do połączenia się z naszym serwerem. | * Do nawiązywania połączeń wykorzystujemy funkcję <code c>connect(int sockfd, struct sockaddr *serv_addr, int addrlen)</code> |
* Nasłuchiwanie można rozpocząć przy pomocy funkcji //listen(int sockfd, int backlog)// | * ''sockfd'' - deskryptor gniazda |
* //sockfd// - deskryptor gniazda. Nasłuchiwanie będzie się odbywać zgodnie z parametrami opisywanymi przez deskryptor. | * ''serv_addr'' - adres hosta docelowego, który możemy otrzymać przy pomocy funckji ''getaddrinfo'' |
* //backlog// - maksymalna liczba połączeń oczekujących na akceptaję. | * ''addrlen'' - długość adresu, najczęściej podaje się wartość ''addrinfo::ai_addrlen'' |
* Ostatnim krokiem rozpoczęcia komunikacji z klientem jest akceptacja jego próby połączenia. Dokonuje się tego za pomocą funkcji: //accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)// | * Dopiero po pomyślnym nawiązaniu połączenia możemy używać ''sockfd'' do komunikowania się z serwerem. |
* Funkcja //accept(3)// jako wartość zwraca nowy deskryptor gniazda który służy do komunikacji z akceptowanym połączeniem. | |
| |
==== Wysyłanie/odbieranie danych ==== | === Nasłuchiwanie === |
| * Rozpoczęcie nasłuchiwania nie wymaga użycia funkcji ''connect'' ponieważ to zdalny klient będzie jej używał do połączenia się z naszym serwerem. |
| * Nasłuchiwanie można rozpocząć przy pomocy funkcji <code c>listen(int sockfd, int backlog)</code> |
| * ''sockfd'' - deskryptor gniazda. Nasłuchiwanie będzie się odbywać zgodnie z parametrami opisywanymi przez deskryptor. |
| * ''backlog'' - maksymalna liczba połączeń oczekujących na akceptaję. |
| * Ostatnim krokiem rozpoczęcia komunikacji z klientem jest akceptacja jego próby połączenia. Dokonuje się tego za pomocą funkcji: <code c>accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)</code> |
| * Funkcja ''accept(2)'' jako wartość zwraca nowy deskryptor gniazda który służy do komunikacji z akceptowanym połączeniem. |
| |
| === Wysyłanie/odbieranie danych === |
* Wszystko w systemach GNU/Linux/Unix jest reprezentowane za pomocą plików - tak więc gniazda również. | * Wszystko w systemach GNU/Linux/Unix jest reprezentowane za pomocą plików - tak więc gniazda również. |
* Wysyłanie/odbieranie danych przez/z gniazd jest bardzo podobne do zapisu/odczytu danych do/z pliku. | * Wysyłanie/odbieranie danych przez/z gniazd jest bardzo podobne do zapisu/odczytu danych do/z pliku. |
* Jest tak podobne że do tego celu można użyć funkcji //write(2)//, //read(2)// :!: | * Jest tak podobne, że do tego celu można użyć funkcji ''write(2)'', ''read(2)'' :!: |
* Jednak system oferuje funckje specjalizowane //send(3)//, //recv(3)// które oferują dodatkową konfigurację. | * Jednak system oferuje funkcje specjalizowane ''send(2)'', ''recv(2)'' które oferują dodatkową konfigurację. |
* Proszę przeczytań manual dla powyższych funkcji zwracając uwagę na: | * Proszę przeczytać manual dla powyższych funkcji zwracając uwagę na: |
* przyjmowane parametry | * przyjmowane parametry |
* zwracane wartości | * zwracane wartości |
| |
==== Zamknięcie połączenia ==== | === Zamknięcie połączenia === |
* Po zakończeniu wysyłania/odbierania danych należy zamknąć połączenie. | * Po zakończeniu wysyłania/odbierania danych należy zamknąć połączenie. |
* Zamknięcie połączenia reprezentowanego przez dany deskryptor można dokonać przy pomocy funkcji //close(3)// | * Zamknięcie połączenia reprezentowanego przez dany deskryptor można dokonać przy pomocy funkcji ''close(2)'' |
* Dla zainteresowanych: porównać funkcję //close(3)// z funkcją //shutdown(3)//. | * Dla zainteresowanych: porównać funkcję ''close(3)'' z funkcją ''shutdown(3)''. |
| |
| |
===== ĆWICZENIA ===== | ===== ĆWICZENIA ===== |
| |
==== Telnet i usługi sieciowe ==== | ==== Sockety w Bashu ==== |
=== SMTP === | |
* [[http://tools.ietf.org/html/rfc821|SMTP]] [[wp>Simple_Mail_Transfer_Protocol]] | * Jest możliwe otworzenie Socketa w Bashu za pomocą następującej składni: <code>exec {deskryptor-pliku}<>/dev/tcp/{host}/{port}</code> |
* ssh student; telnet student 25 | * Np. aby otworzyć dwukierunkowego socketa dla strony Google z portem HTTP i deskryptorem nr 3 (dlaczego akurat taki?) należy napisać: <code>exec 3<>/dev/tcp/www.google.pl/80</code> |
* należy wysłać do siebie (koleżanki/kolegi) email | |
| * Uruchom i przeanalizuj poniższe przykłady: |
| <file bash webpage.sh> |
| #!/bin/bash |
| |
| ### |
| # Połącz się ze stroną internetową i pobierz zawartość strony głównej |
| ### |
| |
=== POP3 === | exec 3<>/dev/tcp/www.google.pl/80 |
* [[http://tools.ietf.org/html/rfc1939|POP3]] [[wp>Post_Office_Protocol]] | echo -e "GET / HTTP/1.1\nHost: www.google.pl\nConnection: close\n\n" >&3 |
* ssh student; telnet student 110 | cat <&3 |
* należy odebrać pocztę ze swojego konta | </file> |
| |
=== HTTP === | <file bash timeserver.sh> |
| #!/bin/bash |
| |
* [[http://tools.ietf.org/html/rfc2616|HTTP]] [[wp>Hypertext_Transfer_Protocol]] | ### |
* założyć własną stronę www: | # Pobierz aktualny czas z serwera NTP |
| ### |
| |
cd ; mkdir public_html ; chmod a+rx public_html ; chmod o+x . ; echo "Jestem $USER" > public_html/index.html | cat </dev/tcp/time.nist.gov/13 |
| </file> |
| |
* oglądnąć własną stronę przez: ''telnet student/borg.ia.agh.edu.pl/~user 80'' | <file bash port-scanner.sh> |
* oglądnąć stronę AGH przez: ''telnet www.agh.edu.pl 80'' | #!/bin/bash |
| |
==== Wprowadzenie do gniazd ==== | ### |
| # Skaner portów (sprawdza które porty są otwarte). |
| # Jako argument wywołania podaj adres serwera, który chcesz przeskanować, |
| # np. ./port-scanner.sh localhost |
| ### |
| |
Przeczytać artykuł | host=$1 |
[[http://www.frostbytes.com/~jimf/papers/sockets/sockets.html|BSD Sockets: A Quick And Dirty Primer]] | port_first=1 |
uruchamiając podane w nim fragmenty kodu. | port_last=65535 |
| for ((port=$port_first; port<=$port_last; port++)) |
| do |
| # echo "Skanowanie portu $port..." |
| timeout 1 bash -c "(echo >/dev/tcp/$host/$port) >/dev/null 2>&1" && echo "$port otwarty!" |
| done |
| </file> |
| |
==== Programowanie gniazd ==== | ==== Programowanie gniazd ==== |
Przeglądnąć artykuł: | Przeglądnąć artykuł: |
[[http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html|Beej's Guide to Network Programming]] | [[http://beej.us/guide/bgnet/html/single/bgnet.html|Beej's Guide to Network Programming]] |
| |
Skompilować i przetestować omówione w nim programy, w tym: | Skompilować i przetestować omówione w nim programy, w tym: |
| |
==== gethostbyname ==== | ==== gethostbyname ==== |
Przeanalizować, skompilować i uruchomić program: | - Proszę przeanalizować, skompilować i uruchomić program:<file c gethostbyname-demo.c> |
| |
<code c> | |
#include <stdio.h> | #include <stdio.h> |
#include <errno.h> | #include <errno.h> |
return 0; | return 0; |
} | } |
</code> | </file> |
* Sprawdzić działanie programu dla ''www.google.pl'' oraz innych wybranych adresów symbolicznych. | - Sprawdzić działanie programu dla ''<nowiki>www.yahoo.com</nowiki>'' oraz innych wybranych adresów symbolicznych. |
* Do powyższego kodu dopisać instrukcje które szczegółowo sprawdzają typ błędu funkcji //gethostbyname// i w zależności od tego wyświetlają odpowiedni komunikat. | - Dopisać instrukcje, które szczegółowo sprawdzają typ błędu funkcji ''gethostbyname'' i w zależności od tego wyświetlają odpowiedni komunikat. |
* Zmodyfikować tak program aby wyświetlał wszystkie adresy IP odnoszące się do podanego adresu. | - Zmodyfikować tak program aby wyświetlał wszystkie adresy IP odnoszące się do podanego adresu. |
| |
==== Komunikator ==== | ==== Serwer ==== |
Poniżej przedstawiony jest kod programu //server.c// | Poniżej przedstawiony jest kod programu //server.c// |
<code c> | <file c server.c> |
/* | /* |
** server.c -- a stream socket server demo | ** server.c -- a stream socket server demo |
} | } |
| |
while(1) { // main accept() loop | sin_size = sizeof their_addr; |
sin_size = sizeof their_addr; | if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { |
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { | perror("accept"); |
perror("accept"); | |
continue; | |
} | |
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); | |
if (!fork()) { // this is the child process | |
close(sockfd); // child doesn't need the listener | |
if (send(new_fd, "Hello, world!\n", 14, 0) == -1) | |
perror("send"); | |
close(new_fd); | |
exit(0); | |
} | |
close(new_fd); // parent doesn't need this | |
} | } |
| printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); |
| if (send(new_fd, "Hello, world!\n", 14, 0) == -1) |
| perror("send"); |
| sleep(5); // just for observing easily that the server cannot serve a few clients concurrently |
| close(new_fd); |
| |
return 0; | return 0; |
} | } |
</code> | </file> |
| |
| === - Komunikator === |
* Należy przerobić powyższy program tak aby działał jako server. Łącząc się za pomocą np. programu //telnet// program powinien umożliwiać prowadzenie dialogu jak popularne komunikatory internetowe (np. gg, tlen, itp). | * Należy przerobić powyższy program tak aby działał jako server. Łącząc się za pomocą np. programu //telnet// program powinien umożliwiać prowadzenie dialogu jak popularne komunikatory internetowe (np. gg, tlen, itp). |
* //Podpowiedź// po akceptacji połączenia program powinien utworzyć dwa procesy potomne, jeden do czytania portu, drugi do pisania. | * Korzystając z programu telnet można połączyć się z serwerem wpisując: <code sh>$ telnet remotehostname XXX</code> gdzie ''remotehostname'' jest nazwą komputera, na którym uruchomiono serwer (''localhost'', jeżeli to ta sama maszyna), a ''XXX'' numerem przypisanego do niego portu. |
| * Podpowiedź: po akceptacji połączenia program powinien utworzyć dwa procesy potomne, jeden do czytania portu, drugi do pisania. |
| |
==== Transfer plików ==== | === - Eternal vigilance == |
* Powyższy komunikator może być z łatwością zmodyfikowany aby zamiast tekstu wysyłał plik. | * Proszę zmodyfikować serwer tak, aby po obsłużeniu klienta nie kończył działania, ale powracał do oczekiwania na kolejne połączenie. |
* Zmodyfikować komunikator tak aby po nawiązaniu połączenia przez klienta rozpoczął wysyłanie pliku. | |
* Zmodyfikować program //client.c// tak aby był zdolny odebrać i zapisać przesyłany plik. | |
| |
==== Użycie Select ==== | |
| |
Patrz: | |
[[http://www.lowtek.com/sockets/select.html|The World of select()]] | |
| |
| === - Obsługa wielu klientów === |
| * Proszę zmodyfikować serwer tak, aby mógł obsługiwać jednocześnie więcej niż jednego klienta. |
| * Podpowiedź: Można użyć funkcji ''fork()'' do tworzenia procesów potomnych - każdy proces potomny będzie obsługiwał jednego klienta. |
| |
| |
* [[http://www.kohala.com/start/|W. Richard Stevens' Home Page]] | * [[http://www.kohala.com/start/|W. Richard Stevens' Home Page]] |
* BSD sockets | * BSD sockets |
http://www.frostbytes.com/~jimf/papers/sockets/sockets.html | * http://www.frostbytes.com/~jimf/papers/sockets/sockets.html |
http://www.lowtek.com/sockets/ | * http://www.lowtek.com/sockets/ |
http://beej.us/guide/bgnet/ | * http://beej.us/guide/bgnet/ |
http://www.uwo.ca/its/doc/courses/notes/socket/ | * http://www.uwo.ca/its/doc/courses/notes/socket/ |
http://gaia.cs.umass.edu/ntu_socket/ | * http://gaia.cs.umass.edu/ntu_socket/ |
http://www.devdaily.com/Dir/Unix/Socket_Programming/ | * http://www.devdaily.com/Dir/Unix/Socket_Programming/ |
http://www.unl.csi.cuny.edu/faqs/sock-faq/html/unix-socket-faq.html | * http://www.unl.csi.cuny.edu/faqs/sock-faq/html/unix-socket-faq.html |
http://www.ibm.com/developerworks/linux/library/l-sockpit/ | * http://www.ibm.com/developerworks/linux/library/l-sockpit/ |
| |
* OpenSSL | * OpenSSL |
http://www.ibm.com/developerworks/linux/library/l-openssl.html | * http://www.ibm.com/developerworks/linux/library/l-openssl.html |
http://www.ibm.com/developerworks/linux/library/l-openssl2.html | * http://www.ibm.com/developerworks/linux/library/l-openssl2.html |
http://www.ibm.com/developerworks/linux/library/l-openssl3.html | * http://www.ibm.com/developerworks/linux/library/l-openssl3.html |
http://www.ibm.com/developerworks/linux/library/l-hisock.html | * http://www.ibm.com/developerworks/linux/library/l-hisock.html |
| |
* TCP/IP | * TCP/IP |
http://userpages.umbc.edu/~jeehye/cmsc491b/lectures/tcpstate/sld001.htm | * http://userpages.umbc.edu/~jeehye/cmsc491b/lectures/tcpstate/sld001.htm |
http://www.tcpipguide.com/free/ | * http://www.tcpipguide.com/free/ |
http://www.ipprimer.com/overview.cfm | * http://www.ipprimer.com/overview.cfm |
http://www.linux-tutorial.info/modules.php?name=MContent&obj=page&pageid=142 | * http://www.linux-tutorial.info/modules.php?name=MContent&obj=page&pageid=142 |
| |
| * Użycie Select |
| * [[http://www.lowtek.com/sockets/select.html|The World of select()]] |
| |