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



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

Komunikacja sieciowa - interfejs gniazd

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

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

Gniazda. S. Samolej: Gniazda 1

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#

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

1. Model klient-serwer

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

Architektura typu klient serwer: uproszczony klient POP3

Klient-Serwer Komunikacja przy pomocy gniazd

Projektowanie oprogramowania systemów KOMUNIKACJA SIECIOWA I SYSTEMY RPC

SUMA KONTROLNA (icmp_cksum) NUMER KOLEJNY (icmp_seq)

Tryb bezpołączeniowy (datagramowy)

Krótkie wprowadzenie do korzystania z OpenSSL

Oprogramowanie komunikacyjne dla Internetu rzeczy Laboratorium nr 4 komunikacja unicastowa IPv6

Programowanie współbieżne i rozproszone

Programowanie sieciowe

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

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

Instytut Teleinformatyki

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

socket(int domain, int type, int protocol)

iseries Programowanie z użyciem gniazd

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

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

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

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

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

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

PROTOKOŁY WARSTWY TRANSPORTOWEJ

Serwer współbieżny połączeniowy

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

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

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

Internet Control Message Protocol Aplikacja ping

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

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

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

Zdalne wywoływanie procedur RPC

Zdalne wywoływanie procedur RPC

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

Zdalne wywoływanie procedur RPC. Dariusz Wawrzyniak 1

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

MODEL WARSTWOWY PROTOKOŁY TCP/IP

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

Programowanie Programowanie z użyciem gniazd

Programowanie Programowanie z użyciem gniazd

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

Programowanie sieciowe

Akademia Techniczno-Humanistyczna w Bielsku-Białej

Programowanie Sieciowe 1

Beej s Guide to Network Programming

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

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

Protokoły sieciowe - TCP/IP

Opis protokołu RPC. Grzegorz Maj nr indeksu:

Serwery współbieżne c.d.

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

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

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

Tworzenie aplikacji rozproszonej w Sun RPC

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

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

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

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

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

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,...

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:

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

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

Wywoływanie procedur zdalnych

Sieci komputerowe 1 DSRG

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

1 Sposób zaliczenia przedmiotu

Komunikacja z użyciem gniazd aplikacje klient-serwer

Wywoływanie procedur zdalnych

Przesyłania danych przez protokół TCP/IP

Mechanizmy pracy równoległej. Jarosław Kuchta

SEGMENT TCP CZ. II. Suma kontrolna (ang. Checksum) liczona dla danych jak i nagłówka, weryfikowana po stronie odbiorczej

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

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

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

Laboratorium - Przechwytywanie i badanie datagramów DNS w programie Wireshark

Obsługa plików Procesy

Transkrypt:

Wykład 4 p. 1/44 Programowanie aplikacji równoległych i rozproszonych Wykład 4 Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska

Gniazda - Wstęp 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. Wykład 4 p. 2/44

Wykład 4 p. 3/44 Domena adresowa 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).

Wykład 4 p. 4/44 Sposób komunikacji 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.

Wykład 4 p. 5/44 Funkcja socketpair Do tworzenia gniazdek w domenie unixowej może zostać wykorzystana funkcja socketpair: #include <sys/types.h> #include <sys/socket.h> 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.

Wykład 4 p. 6/44 Zamknięcie gniazda Funkcję close służy do zamykania gniazda i kończenia połaczenia: int close(int fd); fd - deskryptor gniazda, wynik: 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.

Wykład 4 p. 7/44 Przesyłanie danych 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 + + + +

Wykład 4 p. 8/44 read/write 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. wynik: liczba odczytanych/zapisanych bajtów - w przypadku sukcesu, -1 - w przypadku błędu.

Wykład 4 p. 9/44 socketpair - przykład (1) #include <sys/types.h> #include <sys/socket.h> #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; }

Wykład 4 p. 10/44 socketpair - przykład (2)... 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;

Wykład 4 p. 11/44 socketpair - przykład (3) Przykładowy rezultat działania programu: #0: 1458 #0: proces potomny: 1459 #1: 1459 #1: proces macierzysty: 1458

Komunikacja bezpołaczeniowa Wykład 4 p. 12/44

Wykład 4 p. 13/44 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 - domena internetowa - sieć TCP/IP, PF_UNIX - domena uniksowa - komunikacja lokalna (system plików systemu Unix), PF_APPLETALK - sieć 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).

Wykład 4 p. 14/44 Określanie adresu lokalnego 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.

Wykład 4 p. 15/44 Struktura sockaddr 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 */ };

Funkcje send i sendto 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. wynik: liczba odczytanych/zapisanych bajtów - w przypadku sukcesu, Wykład 4 p. 16/44

Wykład 4 p. 17/44 Funkcje recv i recvfrom 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.

} Wykład 4 p. 18/44 Przykład (I) 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;

Wykład 4 p. 19/44 Przykład (II) 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;

Wykład 4 p. 20/44 Model klient serwer 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 serwera. Gniazda używane przez procesy klienckie nazywane sa gniazdami aktywnymi (one inicjuja połaczenie), natomiast gnizda wykorzystywane w serwerach nazywane sa analogicznie gniazdami pasywnymi.

Komunikacja połaczeniowa Wykład 4 p. 21/44

Wykład 4 p. 22/44 Serwer - przyjmowanie połaczeń (I) 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.

Wykład 4 p. 23/44 Serwer - przyjmowanie połaczeń (II) 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.

Wykład 4 p. 24/44 listen Funkcja listen ustala maksymalna długość kolejki klientów oczekujacych na połaczenie. #include <sys/types.h> #include <sys/socket.h> int listen(int fd, int backlog); fd - deskryptor gniazda, backlog - maksymalna liczba zgłoszeń połaczenia z serwerem. wynik: 0 - w przypadku sukcesu, wartość ujemna - jeśli wystapił bład. W przypadku domeny uniksowej gniazdo musi być strumieniowe i mieć dowiazan a nazwę. W przypadku domeny internetowej, jeśli gniazdo nie ma nazwy, to funkcja listen automatycznie je dowiaże.

Wykład 4 p. 25/44 accept Funkcja accept służy do oczekiwania na połaczenie - proces jest blokowany aż do momentu nawiazania połaczenia przez klienta. W momencie nawiazania połaczenia funkcja accept zwraca nowy deskryptor gniazda, który następnie jest używany do komunikacji z klientem: #include <sys/types.h> #include <sys/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) wynik: 0 - w przypadku sukcesu, -1 - jeśli wystapił bład.

Wykład 4 p. 26/44 Serwer - przykład (I) #include <sys/types.h> #include <sys/socket.h> #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));

Wykład 4 p. 27/44 Server - przykład (II) 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;

Wykład 4 p. 28/44 Łaczenie gniazda z adresem odbiorcy 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 komunikacji w trybie połaczeniowym klient przed rozpoczęciem przesyłania danych za pośrednictwem gniazda musi wywołać procedurę connect w celu uzyskania połaczenia. Gniazda używane w trybie bezpołaczeniowym nie wymagaja podłaczania przed użyciem, ale dzięki podłaczeniu można wysyłać dane do gniazda, nie określajac za każdym razem adresu odbiorcy.

Wykład 4 p. 29/44 connect Funkcja connect: 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 struktury uservaddr. wynik: 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.

} Wykład 4 p. 30/44 Klient - przykład #include <sys/types.h> #include <sys/socket.h> #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;

Wykład 4 p. 31/44 Adres sieciowy 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.

Wykład 4 p. 32/44 Numer portu 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.

Wykład 4 p. 33/44 Funkcja gethostbyname (I) 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 <sys/types.h> #include <sys/socket.h> #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.

Wykład 4 p. 34/44 Funkcja gethostbyname (II) 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.

Wykład 4 p. 35/44 Zmiana kolejności bajtów 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);

Wykład 4 p. 36/44 gethostbyname - przykład (I) 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;

Wykład 4 p. 37/44 gethostbyname - przykład (II) } } 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 << "] = " << inet_ntoa(in) << std::endl; ++host->h_addr_list; } Przykładowy wynik działania programu: Podaj nazwe hosta: icis Oficialna nazwa: icis.pcz.pl Aliasy: Typ adresu: 2 Dlugosc adresu: 4 Lista adresów: [0x6031d0] = 212.87.224.6

Domena internetowa - serwer (I) #include <sys/types.h> #include <sys/socket.h> #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); Wykład 4 p. 38/44

Wykład 4 p. 39/44 Domena internetowa - serwer (II) 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); }

Wykład 4 p. 40/44 Domena internetowa - serwer (III) } 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);

Domena internetowa - klient (I) 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); } if (connect(orginal_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) { perror("blad polaczenia"); exit(4); } Wykład 4 p. 41/44

Wykład 4 p. 42/44 Domena internetowa - klient (II) 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);

Wykład 4 p. 43/44 Lokalne i odległe adresy gniazd Do ustalenia adresu odbiorcy, z którym jest połaczone dane gniazdo służy funkcja: #include <sys/socket.h> int getpeername(int s, struct sockaddr *name, socklen_t *namelen); Procedura getsockname dostarcza lokalnego adresu zwiazanego z danym gniazdem: #include <sys/socket.h> int getsockname(int s, struct sockaddr *name, socklen_t *namelen);

Wykład 4 p. 44/44 Obsługa wielu klientów 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.