Gniazda - Wstęp. Oprogramowanie systemów równoległych i rozproszonych. Sposób komunikacji. Domena adresowa. olas@icis.pcz.pl



Podobne dokumenty
Programowanie aplikacji równoległych i rozproszonych. Wykład 4

Komunikacja sieciowa - interfejs gniazd

Literatura uzupełniająca: W. Richard Stevens, Programowanie zastosowań sieciowych w systemie Unix WNT 1998

Gniazda. S. Samolej: Gniazda 1

Programowanie sieciowe

3. Identyfikacja. SKŁADNIA #include <sys/socket.h> int getpeername(int socket, struct sockaddr *addr, int *addrlen);

Programowanie przy użyciu gniazdek

Iteracyjny serwer TCP i aplikacja UDP

Architektura typu klient serwer: przesyłanie pliku tekstowo oraz logowania do serwera za pomocą szyfrowanego hasła

Gniazda BSD. komunikacja bezpołączeniowa

2. Interfejs gniazd Gniazdo

Podstawowe typy serwerów

Gniazda BSD. Procesy w środowisku sieciowym. Gniazda podstawowe funkcje dla serwera. Gniazda podstawowe funkcje dla klienta

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Programowanie Sieciowe 1

Komputery i Systemy Równoległe Jędrzej Ułasiewicz 1

Gniazda BSD implementacja w C#

1. Model klient-serwer

Sieci komputerowe. Wykład 7: Transport: protokół TCP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Gniazda UDP. Bartłomiej Świercz. Łódź, 3 kwietnia Katedra Mikroelektroniki i Technik Informatycznych. Bartłomiej Świercz Gniazda UDP

Architektura typu klient serwer: uproszczony klient POP3

Tryb bezpołączeniowy (datagramowy)

Projektowanie oprogramowania systemów KOMUNIKACJA SIECIOWA I SYSTEMY RPC

Klient-Serwer Komunikacja przy pomocy gniazd

Oprogramowanie komunikacyjne dla Internetu rzeczy Laboratorium nr 4 komunikacja unicastowa IPv6

SUMA KONTROLNA (icmp_cksum) NUMER KOLEJNY (icmp_seq)

Programowanie współbieżne i rozproszone

Krótkie wprowadzenie do korzystania z OpenSSL

Instrukcja do laboratorium Systemów Operacyjnych. (semestr drugi)

Programowanie sieciowe

ZESZYTY ETI ZESPOŁU SZKÓŁ W TARNOBRZEGU Nr 1 Seria: Teleinformatyka 2013

Instytut Teleinformatyki

1.1 Przykład znajdowanie liczb pierwszych leżących w zadanym zakresie, tryb bezpołączeniowy

socket(int domain, int type, int protocol)

Transport. część 2: protokół TCP. Sieci komputerowe. Wykład 6. Marcin Bieńkowski

Transport. część 2: protokół TCP. Sieci komputerowe. Wykład 6. Marcin Bieńkowski

iseries Programowanie z użyciem gniazd

Aplikacja Sieciowa. Najpierw tworzymy nowy projekt, tym razem pracować będziemy w konsoli, a zatem: File->New- >Project

Gniazda BSD UNIWERSYTET GDAŃSKI WYDZIAŁ MATEMATYKI I FIZYKI. Jacek Nowicki

Obsługa plików. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 25 września 2011

PROTOKOŁY WARSTWY TRANSPORTOWEJ

Gniazda surowe. Bartłomiej Świercz. Łódź,9maja2006. Katedra Mikroelektroniki i Technik Informatycznych. Bartłomiej Świercz Gniazda surowe

Serwer współbieżny połączeniowy

Systemy rozproszone. Krzysztof Banaś Obliczenia równoległe 1

Internet Control Message Protocol Aplikacja ping

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Oprogramowanie systemów równoległych i rozproszonych. Wykład 6

TCP - receive buffer (queue), send buffer (queue)

Laboratorium Systemów Operacyjnych. Ćwiczenie 4. Operacje na plikach

Łącza nienazwane(potoki) Łącza nienazwane mogą być używane tylko pomiędzy procesami ze sobą powiązanymi.

Zdalne wywoływanie procedur RPC 27. października Dariusz Wawrzyniak (IIPP) 1

Sieci komputerowe. Wykład 5: Warstwa transportowa: TCP i UDP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Zdalne wywoływanie procedur RPC

Zdalne wywoływanie procedur RPC

Zdalne wywoływanie procedur RPC 27. października 2010

Model OSI/ISO. Komputer B. Warstwy w modelu OSI aplikacji. aplikacji. prezentacji Komputer A. prezentacji. sesji. sesji. komunikacja wirtualna

Zdalne wywoływanie procedur RPC. Dariusz Wawrzyniak 1

MODEL WARSTWOWY PROTOKOŁY TCP/IP

Warstwa transportowa. Warstwa transportowa. Enkapsulacja. Zapewnienie niezawodnego przesyłania danych /wg ISO/ Transmisja bezpołączeniowa

Programowanie Programowanie z użyciem gniazd

RPC. Zdalne wywoływanie procedur (ang. Remote Procedure Calls )

Programowanie Programowanie z użyciem gniazd

Protokoły sieciowe - TCP/IP

Sieci Komputerowe. Wykład 1: TCP/IP i adresowanie w sieci Internet

Beej s Guide to Network Programming

Programowanie Sieciowe 1

Serwery współbieżne c.d.

Programowanie sieciowe

Akademia Techniczno-Humanistyczna w Bielsku-Białej

Tworzenie aplikacji rozproszonej w Sun RPC

Kurs programowania. Wykład 10. Wojciech Macyna. 05 maja 2016

Podstawy Transmisji Danych. Wykład IV. Protokół IPV4. Sieci WAN to połączenia pomiędzy sieciami LAN

Tunelowanie, kapsułkowanie, XDR. 1. Transmisja tunelowa i kapsułkowanie serwery proxy. 2. Zewnętrzna reprezentacja danych XDR.

DR INŻ. ROBERT WÓJCIK DR INŻ. JERZY DOMŻAŁ ADRESACJA W SIECIACH IP. WSTĘP DO SIECI INTERNET Kraków, dn. 24 października 2016r.

Schemat dla UDP. = możliwe zablokowanie aplikacji KLIENT SERWER. s=socket(...) bind(s,...) recvfrom(s,...) sendto(s,...) recvfrom(s,...

Interfejs programowy Windows Sockets 2. Aplikacja klient-serwer TCP Echo

IPC: Kolejki komunikatów

Pliki. Funkcje tworzące pliki i operujące na nich opisane są w części 2 pomocy systemowej. Tworzenie i otwieranie plików:

Opis protokołu RPC. Grzegorz Maj nr indeksu:

Komunikacja z użyciem gniazd aplikacje klient-serwer

Stos protokołów TCP/IP (ang. Transmission Control Protocol/Internet Protocol)

Sieci komputerowe 1 DSRG

Sieci komputerowe. Zajęcia 3 c.d. Warstwa transportu, protokoły UDP, ICMP

5. Model komunikujących się procesów, komunikaty

W różnych systemach definicje mogą się różnić od powyższej. W linuxie sprobuj man 7 ip do wyswietlenia opisu.

Model warstwowy Warstwa fizyczna Warstwa łacza danych Warstwa sieciowa Warstwa transportowa Warstwa aplikacj. Protokoły sieciowe

IBM i Wersja 7.2. Programowanie Programowanie z użyciem gniazd

Politechnika Łódzka. Instytut Systemów Inżynierii Elektrycznej

Programy typu klient serwer. Programowanie w środowisku rozproszonym. Wykład 5.

Sockety TCP/IP - podstawy. Sieci Komputerowe II Wyk ład 2

Sieci komputerowe. Zajęcia 5 Domain Name System (DNS)

Sieci komputerowe - Wstęp do intersieci, protokół IPv4

Wywoływanie procedur zdalnych

Zadanie 2: transakcyjny protokół SKJ (2015)

Obsługa plików Procesy

5. Algorytmy serwera

Wywoływanie procedur zdalnych

JĘZYK PYTHON - NARZĘDZIE DLA KAŻDEGO NAUKOWCA. Marcin Lewandowski [ mlew@ippt.gov.pl ]

Przesyłania danych przez protokół TCP/IP

Transkrypt:

Gniazda - Wstęp Oprogramowanie systemów równoległych i rozproszonych Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska Domena adresowa 1/?? Podstawa mechanizmu wejścia-wyjścia dla sieci w systemie Unix jest abstrakcyjny mechanizm znany jako gniazda (ang. socket). Gniazdo należy traktować jako jako uogólnienie mechanizmu dostępu do plików udostępniajace jeden z końców łacza komunikacyjnego. Każdy z komunikujacych się ze soba procesów tworzy po swojej stronie jedno gniazdo. Główna różnica pomiędzy deskryptorami plików i gniazdami polega na tym, że system operacyjny wiaże deskryptor z określonym plikiem lub urzadzeniem, natomiast gniazda można tworzyć bez wiazania ich z określonym adresem odbiorcy. Gniazdo jest opisywane za pomoca kombinacji trzech atrybutów: domeny adresowej, sposobu komunikacji i protokołu sieciowego. Sposób komunikacji Wykład 5 p Domena adresowa określa domenę w której będzie realizowana komunikacja: PF_LOCAL (PF_UNIX) - komunikacja w obrębie jednej maszyny, PF_INET - Internet, czyli używamy protokołów z rodziny TCP/IP, PF_IPX - protokoły IPX/SPX (Novell), PF_PACKET - niskopoziomowy interfejs do odbierania pakietów w tzw. surowej (ang. raw) postaci. Zamiennie używa się notacji PF_xxx (PF - Protocol Family) oraz AF_xxx (AF - Address Family). Gniazda typu SOCK_STREAM - komunikacja w modelu połaczeniowym (zwykle zwiazane z protokołem TCP warstwy transportowej) Gniazda typu SOCK_DGRAM - komunikacja w modelu bezpołaczeniowym korzystajaca z tzw. datagramów (zwykle zwiazane z protokołem UDP warstwy transportowej) Gniazda typu SOCK_RAW - komunikacja na niskim poziomie - dostęp do surowych pakietów na poziomie warstwy sieciowej TCP/IP. 3/?? Wykład 5 p

Funkcja socketpair Zamknięcie gniazda Do tworzenia gniazdek w domenie unixowej może zostać wykorzystana funkcja socketpair: int socketpair(int family, int type, int protocol, int sockvec[2]); Funkcja zwraca deskryptor gniazda. family - oznacza domenę komunikacyjną (czyli rodzinę protokołów adresów) w jakiej będzie funkcjonować nowe gniazdo. W systemie Linux jedyna obsługiwana domena jest PF_UNIX. type - określa rodzaj gniazda, protocol - protokół z jakiego gniazdo korzysta, sockver - gdy nie wystapi bład zostana do tej zmiennej zapisana para deskryptorów gniazd w domenie Unixa. Otrzymuje się w ten sposób łacze strumieniowe z możliwościa dwustronnej komunikacji. Funkcję close służy do zamykania gniazda i kończenia połaczenia: int close(int fd); fd - deskryptor gniazda, 0 - w przypadku sukcesu, -1 - jeśli wystapił bład. Przy wywoływaniu funkcji close zmniejszany jest licznik odwołań do deskryptora. Gdy proces się kończy, system operacyjny zamyka wszystkie gniazda, które były wówczas otwarte. Przesyłanie danych 5/?? read/write Wykład 5 p Przesyłanie danych poprzez gniazda może odbywać się z wykorzystaniem pięciu różnych funkcji systemowych: send/write, sendto/recvfrom, sendmsg/recvmsg, write/read, writev/readv. Procedury send/recv, sendto/redvfrom oraz sendmsg/recvmsg wymagaja aby gniazdo było przyłaczone, gdyż nie umożliwiaja podania adresu odbiorcy. read/write readv/writev + send/recv + wiele dodatkowe adres informacje buforów znaczniki partnera kontrolne sendto/recvfrom + + sendmsg/recvmsg + + + + ssize_t read(int fd, void *buf, size_t count) ssize_t write(int fd, const void *buf, size_t count) fd - deskryptor, buff - adres danych do odczytania/zapisania, length - rozmiar danych do odczytania/zapisania. liczba odczytanych/zapisanych bajtów - w przypadku sukcesu, -1 - w przypadku błędu. 7/?? Wykład 5 p

socketpair - przykład (1) socketpair - przykład (2) #include <unistd.h> #include <iostream> const int SIZE = 40; int main() int sockets[2]; socketpair(pf_unix, SOCK_STREAM, 0, sockets); int pid = fork(); if (pid == 0) // proces potomny close(sockets[1]); char buf[size]; sprintf(buf, "proces potomny: %d", getpid()); write(sockets[0], buf, sizeof(buf) + 1); read(sockets[0], buf, SIZE); close(sockets[0]); std::cout << "#1: " << getpid() << "\n#1: " << buf << std::endl;... else // proces macierzysty close(sockets[0]); char buf[size]; read(sockets[1], buf, SIZE); std::cout << "#0: " << getpid() << "\n#0: " << buf << std::endl; sprintf(buf, "proces macierzysty: %d", getpid()); write(sockets[1], buf, sizeof(buf) + 1); close(sockets[1]); return 0; socketpair - przykład (3) 9/?? Model klient serwer Przykładowy rezultat działania programu: #0: 1458 #0: proces potomny: 1459 #1: 1459 #1: proces macierzysty: 1458 Termin serwer odnosi się do każdego programu, który oferuje usługę dostępna poprzez sieć. Serwer przyjmuje przez sieć zamówienia, wykonuje usługę i zwraca wyniki zamawiajacemu. Klientem staje się program, który wysyła zamówienie do serwera i czeka na odpowiedź. W przypadku modelu klient serwer każde połaczenie sieciowe jest tworzone przez klienta wysyłajacego żadania do stale oczekujacego na nie klienta. Gniazda używane przez procesy klienckie nazywane sa gniazdami aktywnymi (one inicjuja połaczenie), natomiast gnizda wykorzystywane w serwerach nazywane sa analogicznie gniazdami pasywnymi. 11/??

Komunikacja połaczeniowa Tworzenie gniazd Użytkownik identyfikuje gniazda za pomoca deskryptorów (wykorzystywanych przy każdorazowym odwoływaniu się do gniazda) Funkcja socket tworzy nowe gniazdo i zwraca jego deskryptor: int socket (int family, int type, int protocol); family - oznacza domenę komunikacyjną (czyli rodzinę protokołów adresów) w jakiej będzie funkcjonować nowe gniazdo, np: PF_INET - intersieć TCP/IP, PF_UNIX - system plików systemu Unix, PF_APPLETALK - itersieć firmy Apple Computer Incorporated, type - określa rodzaj gniazda, protocol - protokół z jakiego gniazdo korzysta (w przypadku 0 będzie to domyślny protokół dla danego rodzaju gniazda). Określanie adresu lokalnego 13/?? Struktura sockaddr Poczatkowo nowo utworzone gniazdo nie jest zwiazane z żadnym adresem lokalnym ani odległym. Po utworzeniu gniazda serwer wiaże z nim adres lokalny za pomoca funkcji systemowej bind: int bind(int fd, struct sockaddr *my_addr, int addrlen) fd - deskryptor gniazda, my_addr - wskaźnik na strukturę adresów odpowiednia dla rodziny protokołów, do której należy gniazdo, addrlen - rozmiar tej struktury. Dla domeny uniksowej: struct sockaddr_un short sun_family; /* AF_UNIX */ char sun_data; /* ścieżka */ ; Dla domeny internetowej: struct sockaddr_in short sin_family; /* AF_INET */ u_short sin_port; /* 16-bitowy numer portu */ struct in_addr sin_addr; /* 32-bitowy internetowy */ /* adres hosta */ char sin_zero[8]; /* zarezerwowane */ ; 15/??

Serwer - przyjmowanie połaczeń (I) Serwer - przyjmowanie połaczeń (II) Serwer używa funkcji socket, bind i listen do utworzenia gniazda. Wywołanie bind wiaże gniazdo z powszechnie znanym portem protokołu, ale nie powoduje podłaczenia gniazda do żadnego odległego odbiorcy. Zamiast odległego odbiorcy podaje się adres uogólniajacy (ang. wildcard), by gniazdo mogło przyjmować połaczenia od dowolnych klientów. Po utworzeniu gniazda serwer czeka na połaczenia. W tym celu wywołuje procedurę systemowa accept. Gdy nadchodzi żadanie, system wypełnia strukturę addr adresem klienta, który je zgłosił. Następnie system tworzy nowe gniazdo, które jest połaczone z klientem i dostarcza wywołujacemu programowi deskryptor tego gniazda. Pierwotne gniazdo nadal nie jest połaczone z żadnym konkretnym odległym klientem i pozostaje w dalszym ciagu otwarte. Dzięki temu serwer nadal może czekać na żadania nadchodzace za pośrednictwem tego gniazda. Wywołanie accept kończy się po nadejściu żadania połaczenia. Serwer może obsługiwać nadchodzace żadania po kolei, badź też współbieżnie. listen 17/?? accept Funkcja listen ustala maksymalna długość kolejki klientów oczekujacych na połaczenie. int listen(int fd, int backlog); fd - deskryptor gniazda, backlog - maksymalna liczba zgłoszeń połaczenia z serwerem. 0 - w przypadku sukcesu, wartość ujemna - jeśli wystapił bład. W przypadku rodziny Unixa gniazdo musi być strumieniowe i mieć dowiazan a nazwę. W przypadku rodziny Internetu, jeśli gniazdo nie ma nazwy, to listen automatycznie je dowiaże. Funkcja accept służy do oczekiwania na połaczenie - proces jest blokowany aż do momentu nawiazania połaczenia przez inny proces. W momencie nawiazania połaczenia i funkcja zwraca nowy deskryptor gniazda, który następnie jest używany do wymiany danych z klientem: #include &ltsys/types.h> #include &ltsys/socket.h> int accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen); fd - deskryptor gniazda, upeer_sockaddr - wskaźnik na nazwę gniazda klienta (jako dodatkowy wynik) upeer_addrlen - rozmiar nazwy upeer_sockaddr (jako dodatkowy wynik) 0 - w przypadku sukcesu, -1 - jeśli wystapił bład. 19/??

Serwer - przykład (I) Server - przykład (II) #include <sys/un.h> #include <unistd.h> #include <iostream> const char name[] = "my_socket"; int main() int orginal_socket = socket(af_unix, SOCK_STREAM, 0); sockaddr_un server_address; server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, name); unlink(name); bind(orginal_socket, (sockaddr*)&server_address, sizeof(server_address.sun_family) + sizeof(server_address.sun_path)); listen(orginal_socket, 1); sockaddr_un client_address; socklen_t client_length = sizeof(client_address); int new_socket = accept(orginal_socket, (sockaddr*)&client_address, &client_length); char buf[255]; read(new_socket, buf, sizeof(buf)); std::cout << buf << std::endl; close(new_socket); close(orginal_socket); unlink(name); return 0; Łaczenie gniazda z adresem odbiorcy 21/?? connect Bezpośrednio po utworzeniu gniazda znajduje się ono w stanie niepołaczonym, co oznacza, że nie jest ono zwiazane z żadnym adresatem. Procedura systemowa connect trwale łaczy gniazdo z adresem odbiorcy, zmieniajac jednocześnie stan gniazda na połaczony. W przypadku gniazda odpowiadajacego niezawodnym strumieniom klient przed rozpoczęciem przesyłania danych za pośrednictwem gniazda musi wywołać procedurę connect w celu uzyskania połaczenia. Gniazda używane z usługami bezpołaczeniowego przesyłania datagramów nie wymagaja podłaczania przed użyciem, ale dzięki podłaczeniu można wysyłać dane do gniazdka, nie określajac adresu odbiorcy. Funkcja connect umożliwia nawiazanie połaczenia przy użyciu podanego gniazda z gniazdem nasłuchujacym: int connect(int fd, struct sockaddr *uservaddr, int addrlen); fd - deskryptor gniazda, uservaddr - struktura określajaca adres, z którym należy zwiazać wskazane gniazdo, addrlen - rozmiar adresu serwera. 0 - w przypadku sukcesu, wartość ujemna - w przypadku błędu, np: EBADF - fd jest nieprawidłowym deskryptorem, ENOTSOCK - fd nie jest deskryptorem gniazda, EISCONN - jest już zrealizowane polaczenie. 23/??

Klient - przykład Komunikacja bezpołaczeniowa #include <sys/un.h> #include <unistd.h> #include <iostream> const char name[] = "my_socket"; int main() int orginal_socket = socket(af_unix, SOCK_STREAM, 0); sockaddr_un server_address; server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, name); connect(orginal_socket, (sockaddr*)&server_address, sizeof(server_address.sun_family) + sizeof(server_address.sun_path)); char buf[] = "hello"; write(orginal_socket, buf, sizeof(buf)); close(orginal_socket); return 0; 25/?? Funkcje send i sendto Funkcje recv i recvfrom ssize_t send(int s, const void *buf, size_t len, int flags); ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); s - deskryptor gniazda, przez które wysyłamy dane, buf - wskaźnik do bufora, który chcemy wysłać, len - liczba bajtów bufora do wysłania, flags - dodatkowe flagi (np. codemsg_dontwait - Przełacza funkcję w tryb nieblokujacy), to - wskaźnik do struktury zawierajacej adres odbiorcy, addrlen - rozmiar struktury zawierajacej adres. liczba odczytanych/zapisanych bajtów - w przypadku sukcesu, -1 - w przypadku błędu. 27/?? ssize_t recv(int s, void *buf, size_t len, int flags); ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); s - deskryptor gniazda, przez które odbieramy dane, buf - adres (wskaźnik) bufora, który będzie zawierał dane po ich odebraniu, len - rozmiar bufora (maksymalna liczba bajtów, która można jednorazowo odebrać), flags - dodatkowe flagi, to - wwskaźnik do struktury, przez która zwrócony zostanie adres nadawcy, addrlen - rozmiar struktury zawierajacej adres.

Przykład - serwer Przykład - klient const char name[] = "my_socket"; int main() int orginal_socket = socket(af_unix, SOCK_DGRAM, 0); unlink(name); sockaddr_un server_address; server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, name); bind(orginal_socket, (sockaddr*)&server_address, sizeof(server_address.sun_family) + sizeof(server_address.sun_path)); char buf[255]; while (true) socklen_t client_length; recvfrom(orginal_socket, buf, sizeof(buf), 0, (sockaddr*)&server_address, &client_length); std::cout << buf << std::endl; close(orginal_socket); return 0; 29/?? Adres sieciowy const char name[] = "my_socket"; int main(int argc, char** argv) int orginal_socket = socket(af_unix, SOCK_DGRAM, 0); sockaddr_un server_address; server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, name); bind(orginal_socket, (sockaddr*)&server_address, sizeof(server_address.sun_family) + sizeof(server_address.sun_path)); sendto(orginal_socket, argv[1], sizeof(argv[1]), 0, (sockaddr*)&server_address, sizeof(sockaddr)); close(orginal_socket); return 0; Numer portu Każdy host w sieci ma przynajmniej dwa tylko właściwe sobie adresy: 48-bitowy adres ethernetowy (przypisywany ethernetowej karcie sieciowej przez producenta), 32-bitowy adres internetowy (tzw. numer IP). W interakcji z użytkownikiem jest on podzielony na cztery 8-bitowe liczby dziesiętne separowane kropkami. Każda z tych liczb może się zawierać w przedziale od 0 do 255, choć wartości brzegowe sa używane jako wartości specjalnego przeznaczenia. Numer portu jest liczba 16-bitowa bez znaku. Jednoznacznie identyfikuje połaczenie sieciowe w ramach jednego adresu IP. Para (adres IP, numer portu) jednoznacznie określa komputer w sieci, jak również konkretny proces działajacy na tym komputerze. 31/??

Funkcja gethostbyname (I) Funkcja gethostbyname (II) W przypadku domeny internetowej procesy musza dysponować swoimi adresami hostów i numerami portów, aby mogły ze soba nawiazać kontakt. Funkcja gethostbyname zwraca pełne informacje o hoście, którego nazwę podano w argumentach: #include <netinet/in.h> #include <netdb.h> hostent* gethostbyname(const char* name); name - wskaźnik na napis zawierajacy nazwę hosta. Jeśli nazwa hosta zostanie znaleziona funkcja zwróci wskaźnik na strukturę hostent, w przeciwnym wypadku zwróci NULL. struct hostent char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; #define h_addr h_addr_list[0] ; h_name - oficjalna nazwa hosta, h_aliases - lista aliasów, h_addrtype - typ adresu hosta, h_length - długość adresu, h_addr_list - lista adresów z serwera nazw. Zmiana kolejności bajtów 33/?? gethostbyname - przykład (I) Poszczególne typy komputerów różnia się sposobem przechowywania liczb, a protokoły TCP/IP określaja niezależny od maszyny standard porzadku bajtów liczb. System Unix BSD oferuje cztery procedury biblioteczne służace do konwersji między porzadkiem bajtów na danym komputerze oraz sieciowym porzadkiem bajtów (<netinet/in.h>): Do zamiany liczby z reprezentacji sieciowej do reprezentacji lokalnej (network to host) służa funkcje: uint16_t ntohs(uint16_t netshort); uint32_t ntohl(uint32_t netlong); Do konwersji liczb z porzadku danego komputera na porzadek sieciowy (host to network) służa funkcje: uint16_t htons(uint16_t hostshort); uint32_t htonl(uint32_t hostlong); hostent *host; std::string hostname; std::cout << "Podaj nazwe hosta: " << std::flush; std::getline(std::cin, hostname); host = gethostbyname(hostname.c_str()); if (host!= NULL) std::cout << "Oficialna nazwa: " << host->h_name << std::endl << "Aliasy: " << std::endl; while (*host->h_aliases) std::cout << " " << *host->h_aliases << std::endl; ++host->h_aliases; std::cout << "Typ adresu: " << host->h_addrtype << std::endl << "Dlugosc adresu: " << host->h_length << std::endl << "Lista adresów: " << std::endl; 35/??

gethostbyname - przykład (II) Domena internetowa - serwer (I) while (*host->h_addr_list) in_addr in; memcpy(&in.s_addr, *host->h_addr_list, sizeof(in.s_addr)); std::cout << "[" << host->h_addr_list << "] = " << *host->h_addr_list << inet_ntoa(in) << std::endl; ++host->h_addr_list; Przykładowy wynik działania programu: Podaj nazwe hosta: localhost Oficialna nazwa: localhost Aliasy: Typ adresu: 2 Dlugosc adresu: 4 Lista adresów: [0x804a648] = 127.0.0.1 Domena internetowa - serwer (II) 37/?? #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <iostream> #include "local.h" int main() int orginal_socket = socket(af_inet, SOCK_STREAM, 0); if (orginal_socket < 0) perror("blad generowania"); exit(1); sockaddr_in server_address; memset(&server_address, 0, sizeof(sockaddr_in)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(inaddr_any); server_address.sin_port = htons(port); Domena internetowa - serwer (III) if (bind(orginal_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) perror("blad dowiazania"); exit(2); if (listen(orginal_socket, 5) < 0) perror("blad nasluchu"); exit(3); do sockaddr_in client_address; socklen_t client_len = sizeof(client_address); int new_socket = accept(orginal_socket, (sockaddr*)&client_address, &client_len); if (new_socket < 0) perror("blad akceptowania"); exit(4); if (fork() == 0) int len; const int BUFSIZE = 255; char buf[bufsize]; while ((len = read(new_socket, buf, BUFSIZE)) > 0) for (int i = 0; i < len; i++) buf[i] = toupper(buf[i]); write(new_socket, buf, len); if (buf[0] ==. ) break; close(new_socket); exit(0); else close(new_socket); while (true); 39/??

Domena internetowa - klient (I) Domena internetowa - klient (II) int main(int argc, char** argv) hostent *host = gethostbyname(argv[1]); sockaddr_in server_address; memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; memcpy(&server_address.sin_addr, host->h_addr, host->h_length); server_address.sin_port = htons(port); int orginal_socket = socket(af_inet, SOCK_STREAM, 0); if (orginal_socket < 0) perror("blad generowania"); exit(3); char buf[255]; std::string line; do std::cout << "> " << std::flush; getline(std::cin, line); write(orginal_socket, line.c_str(), line.size()+1); read(orginal_socket, buf, 255); std::cout << buf << std::endl; while (line[0]!=. ); close(orginal_socket); exit(0); if (connect(orginal_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) perror("blad polaczenia"); exit(4); Lokalne i odległe adresy gniazd 41/?? Obsługa wielu klientów Do ustalenia adresu odbiorcy, z którym jest połaczone dane gniazdo służy funkcja: int getpeername(int s, struct sockaddr *name, socklen_t *namelen); Procedura getsockname dostarcza lokalnego adresu zwiazanego z danym gniazdem: int getsockname(int s, struct sockaddr *name, socklen_t *namelen); Funkcje accept, send, recv, sendto, recfrom sa blokujace. Aby serwer mógł obsługiwać wielu klientów należy: utworzyć dla każdego klienta oddzielny proces, obsługiwać poszczególnych klientów przy użyciu dodatkowych watków, wykorzystać funkcję select. 43/??