4. Algorytmy klienta



Podobne dokumenty
Iteracyjny serwer TCP i aplikacja UDP

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

Podstawowe typy serwerów

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

Programowanie Sieciowe 1

2. Interfejs gniazd Gniazdo

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

Programowanie przy użyciu gniazdek

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

Gniazda BSD. komunikacja bezpołączeniowa

SUMA KONTROLNA (icmp_cksum) NUMER KOLEJNY (icmp_seq)

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

Klient-Serwer Komunikacja przy pomocy gniazd

Instytut Teleinformatyki

Komunikacja sieciowa - interfejs gniazd

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Architektura typu klient serwer: uproszczony klient POP3

1. Model klient-serwer

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

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

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

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

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

Przesyłania danych przez protokół TCP/IP

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

Gniazda BSD implementacja w C#

Tryb bezpołączeniowy (datagramowy)

Programowanie sieciowe

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

PROTOKOŁY WARSTWY TRANSPORTOWEJ

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

1. Model klient-serwer

Sieci komputerowe 1 DSRG

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

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

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

Programowanie Sieciowe 1

Oprogramowanie komunikacyjne dla Internetu rzeczy Laboratorium nr 4 komunikacja unicastowa IPv6

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

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

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

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

5. Algorytmy serwera

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

Zdalne wywołanie procedur. Krzysztof Banaś Systemy rozproszone 1

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

Programowanie współbieżne i rozproszone

Laboratorium z systemów operacyjnych. System plików - funkcje systemowe. Anna Wojak

Wykład 4: Protokoły TCP/UDP i usługi sieciowe. A. Kisiel,Protokoły TCP/UDP i usługi sieciowe

Podstawowe typy serwerów

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

Serwery współbieżne c.d.

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

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

Akademia Techniczno-Humanistyczna w Bielsku-Białej

Protokoły sieciowe - TCP/IP

Zdalne wywoływanie procedur RPC. Dariusz Wawrzyniak 1

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

MODEL WARSTWOWY PROTOKOŁY TCP/IP

Zdalne wywoływanie procedur RPC

Zdalne wywoływanie procedur RPC

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Skąd dostać adres? Metody uzyskiwania adresów IP. Statycznie RARP. Część sieciowa. Część hosta

socket(int domain, int type, int protocol)

Sieci komputerowe Warstwa transportowa

MODEL OSI A INTERNET

ARP Address Resolution Protocol (RFC 826)

Serwer współbieżny połączeniowy

IPC: Kolejki komunikatów

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

DR INŻ. ROBERT WÓJCIK DR INŻ. JERZY DOMŻAŁ

Krótkie wprowadzenie do korzystania z OpenSSL

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

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

Opis protokołu RPC. Grzegorz Maj nr indeksu:

KONFIGURACJA SIECIOWA SYSTEMU WINDOWS

Instytut Teleinformatyki

ĆWICZENIE 5. TEMAT: OBSŁUGA PORTU SZEREGOWEGO W PAKIECIE KEILuVISON WYSYŁANIE PORTEM SZEREGOWYM

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

Zarządzanie ruchem w sieci IP. Komunikat ICMP. Internet Control Message Protocol DSRG DSRG. DSRG Warstwa sieciowa DSRG. Protokół sterujący

Enkapsulacja RARP DANE TYP PREAMBUŁA SFD ADRES DOCELOWY ADRES ŹRÓDŁOWY TYP SUMA KONTROLNA 2 B 2 B 1 B 1 B 2 B N B N B N B N B Typ: 0x0835 Ramka RARP T

Przykład. Podaj nazwę domenową hosta a odczytaj jego adres IP, lub odwrotnie:

Projektowanie oprogramowania systemów KOMUNIKACJA SIECIOWA I SYSTEMY RPC

1 Moduł Diagnostyki Sieci

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

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

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Remote Quotation Protocol - opis

TCP/IP formaty ramek, datagramów, pakietów...

Wybrane działy Informatyki Stosowanej

Architektury systemów rozproszonych LABORATORIUM. Ćwiczenie 1

Wywoływanie procedur zdalnych

Zadanie 2: transakcyjny protokół SKJ (2015)

Gniazda. S. Samolej: Gniazda 1

Sieci komputerowe - Protokoły warstwy transportowej

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

Aplikacja Sieciowa wątki po stronie klienta

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

TRX API opis funkcji interfejsu

Transkrypt:

4. Algorytmy klienta 4.1. Algorytm działania programu klienckiego typu połączeniowego (TCP) 1. Określ adres IP i numer portu dla serwera, z którym należy nawiązać komunikację. 2. Uzyskaj przydział gniazda (wywołanie funkcji socket). 3. Ustal lokalny numer portu i adres IP. 4. Uzyskaj połączenie gniazda z serwerem (wywołanie funkcji connect). 5. Komunikuj się z serwerem za pomocą protokołu warstwy użytkowej (wymaga to zazwyczaj wysyłania zapytań na przykład przy pomocy funkcji systemowej write i odbieranie odpowiedzi na przykład za pomocą funkcji read). 6. Zamknij połączenie (wywołanie funkcji close). Ad 3. Programy klienckie używające protokołu TCP zazwyczaj nie określają adresu lokalnego punktu końcowego ani numeru portu, lecz pozostawiają oprogramowaniu TCP/IP wybór zarówno właściwego adresu IP, jak i wolnego numeru portu. Ad 4. Funkcja connect: sprawdza poprawność odwołania do gniazda wypełnia w strukturze opisującej gniazdo pole adresu odległego hosta wybiera odpowiedni lokalny adres IP i numer portu (o ile nie zostały przypisane) i umieszcza w strukturze opisującej gniazdo inicjuje nawiązanie połączenia TCP; z funkcji powraca się wtedy, kiedy będzie ustanowione połączenie albo pojawi się błąd. Funkcja connect() nie może być ponawiana bez uprzedniego otworzenia nowego gniazda. Ad 5. Przebieg współpracy z serwerem określa protokół komunikacji. TCP jest protokołem strumieniowym, odbiór danych musi być wykonywany iteracyjnie dane mogą przychodzić podzielone na porcje. Należy zapewnić odbiór całej porcji danych przeznaczonej do przetwarzania. Ad 6. Do zamykania połączenia służy funkcja close. Czasem jednak klient wie, że chce zakończyć połączenie, ale nie wie czy otrzymał już wszystkie dane wysyłane przez serwer. Serwer może przesyłać dowolnie dużo danych w odpowiedzi na zapytanie klienta. Wtedy klient może wykonać operację częściowego zamknięcia połączenia po wysłaniu ostatniego zapytania służy do tego funkcja shutdown. Klient przekazuje do oprogramowania warstwy niższej informację, że nie będzie już wysyłał danych, ale gniazdo nie zostaje jeszcze zwolnione. W rezultacie serwer otrzymuje sygnał końca pliku. Może zatem zamknąć to połączenie po wysłaniu ostatniej odpowiedzi. 1

Przykład komunikacji z serwerem przez połączenie TCP #define BDL 120 /* dlugosc bufora char pytanie="czy jestes gotowy?"; /* tekst do przesłania char buf[bdl]; /* bufor na odpowiedź char bptr; /* wskaźnik do bufora int n; /* liczba przeczytanych bajtów int bufdl; /* ilość wolnego miejsca w buforze bptr=buf; bufdl=bdl; /* wyślij zapytanie write(gniazdo,pytanie,strlen(pytanie)); /* czytaj odpowiedź (może przyjść podzielona na części) while ((n=read(gniazdo,bptr,bufdl))>0) { bptr +=n; /* przesuń wskaźnik za wczytane dane bufdl -=n; /* zmniejsz licznik wolnych miejsc Wysyłanie danych do gniazda TCP Program użytkowy bufor programu użytkowego write() proces użytkownika jądro systemu TCP bufor wysyłkowy gniazda IP segmenty TCP (MSS) Warstwa łącza pakiety IPv4 (MTU) Każde gniazdo TCP ma określony bufor wysyłkowy dla danych, które ma wysyłać. Funkcja write powoduje, że jądro kopiuje dane z bufora programu użytkownika do bufora wysyłkowego gniazda. Jeśli w buforze wysyłkowym nie ma miejsca, proces się usypia. Powrót z write będzie wykonany dopiero po skopiowaniu ostatniego bajtu do bufora wysyłkowego. Oprogramowanie TCP pobiera dane z bufora wysyłkowego i przesyła je do warstwy IP porcjami o rozmiarze MSS maksymalny rozmiar segmentu (ang. Maximum Segment Size), uzgodnionym z partnerem., dołączając nagłówek TCP. Zwykłe MSS MTU 40. Oprogramowanie IP dołącza swój nagłówek i przesyła do warstwy łącza danych. 2

write() - przesyłanie danych do odległego komputera (klient, serwer) Funkcja write służy do przesłania danych do komputera odległego. Funkcja zwraca liczbę poprawnie przesłanych bajtów lub 1 w wypadku błędu. Kod błędu jest umieszczany w errno. Składnia jest następująca: int write(int socket, char* buf, int buflen) Każde gniazdo TCP ma określony bufor wysyłkowy dla danych, które ma wysyłać. Funkcja write powoduje, że jądro kopiuje dane z bufora programu użytkownika do bufora wysyłkowego gniazda. Jeśli w buforze wysyłkowym nie ma miejsca, proces się usypia. Powrót z write będzie wykonany dopiero po skopiowaniu ostatniego bajtu do bufora wysyłkowego. read() - odbieranie danych z gniazda (klient, serwer) Funkcja read służy do odebrania danych wejściowych z gniazda. Funkcja zwraca 0 w razie końca pliku, wartość określającą liczbę przeczytanych bajtów lub 1 w wypadku błędu. Kod błędu jest umieszczany w errno. Składnia jest następująca: int read(int socket, char* buf, int buflen) send() - wysyłanie danych do odległego komputera (dla gniazda połączonego) SKŁADNIA #include <sys/socket.h> int send(int sockfd, const void* buff, size_t nbytes, int flags); OPIS Funkcja send służy do przesyłania danych do odległego komputera. Gniazdo musi być w stanie connected. ARGUMENTY sockfd - deskryptor gniazda, buff - adres bufora zawierającego dane do wysłania, nbytes - liczba bajtów danych w buforze, flags- opcje sterowania transmisja lub opcje diagnostyczne (lub 0) WARTOŚĆ ZWRACANA Funkcja zwraca liczbę wysłanych bajtów, lub -1 w przypadku błędu. recv() - odbieranie danych z gniazda (dla gniazda połączonego) SKŁADNIA #include <sys/socket.h> int recv(int sockfd, void *buff, size_t nbytes, int flags); OPIS Znaczenie argumentów: sockfd - deskryptor gniazda, buff - adres bufora, w którym zostaną umieszczone otrzymane dane, nbytes - liczba bajtów w buforze, flags- opcje sterowania transmisja lub opcje diagnostyczne, WARTOŚĆ ZWRACANA Funkcja zwraca liczbę otrzymanych bajtów, lub -1 w przypadku błędu. 3

Budowanie komunikatów Protokół TCP jest protokołem strumieniowym. Aplikacja często działa na komunikatach o określonej strukturze. Odbiorca musi wiedzieć w jaki sposób wyróżnić początek i koniec komunikatu, ewentualnie początek i koniec pól składowych komunikatu. Można wyróżnić przypadki: znana jest długość odbieranego komunikatu znany jest znak kończący dane zawarte w pojedynczym komunikacie, np. znak nowej linii każdy komunikat może być zmiennej długości i nie ma specjalnego znaku kończącego dane, informacja o długości komunikatu jest przesyłana w ustalony sposób Przykład funkcji czytającej dla przypadku, w którym znana jest długość komunikatu, wykorzystywana jest funkcja read(): /* readn - czytaj dokładnie n bajtów int readn(int s, char *bufor, size_t dl) { int licznik; /* ile bajtów jeszcze do przeczytania int rl; /* ile bajtów otrzymano licznik = dl; while ( licznik > 0 ) { rl = recv( s, bufor, licznik, 0 ); /* lub read() if ( rl < 0 ) { if ( errno == EINTR ) /* przerwano? continue; return -1; /* zwróć błąd if ( rl == 0 ) /* koniec? return dl - licznik; bufor += rl; licznik -= rl; return dl; W przypadku użycia funkcji recv() można wykorzystać opcję (MSG_WAITALL), która powoduje, że powrót z funkcji następuje dopiero po wypełnieniu całego bufora. 4

4.2. Algorytm działania programu klienckiego typu bezpołączeniowego (UDP) 1. Określ adres IP i numer portu dla serwera, z którym należy nawiązać komunikację. 2. Uzyskaj przydział gniazda. 3. Ustal lokalny numer portu i adres IP (zdaj się na oprogramowanie warstwy UDP i IP). 4. Podaj adres serwera, do którego mają być wysyłane komunikaty. 5. Realizuj własne zadania komunikując się z serwerem za pomocą protokołu poziomu użytkowego (wyślij zapytanie czekaj na odpowiedź). 6. Zamknij połączenie. Ad 4. Są dwa tryby działania programu klienckiego UDP: połączeniowy do gniazda przypisywany jest adres IP i numer portu serwera (funkcja connect ), ale nie jest inicjowana żadne połączenie z serwerem. bezpołączeniowy gniazdo nie jest związane z żadnym punktem końcowym, w każdym datagramie trzeba podać adres docelowy. Ad 5. Po wykonaniu connect klient może wywołać funkcję read, żeby odczytać datagram i write, żeby go wysłać. Do odebrania lub wysłania całego komunikatu wystarczy pojedyncze wywołanie takiej funkcji. W wypadku gniazda bezpołączeniowego trzeba używać funkcji sendto i recvfrom, które pozwalają podać adres punktu końcowego. Ad 6. Funkcja close zamyka gniazdo i zwalnia związane z nim zasoby systemowe. Po jej wywołaniu oprogramowanie UDP będzie odrzucać wszystkie komunikaty wysyłane do portu związanego z danym gniazdem, jednak nie zawiadomi o tym serwera. Zamknięcie gniazda może być również zrealizowane przy pomocy funkcji shutdown. Komunikacja jest zamykana w jednym kierunku bez powiadamianie o tym serwera. Protokół UDP jest protokołem zawodnym. Trzeba wbudować mechanizmy zabezpieczające (szczególnie w sieciach złożonych), w szczególności: odmierzające limit czasu na transmisję inicjujące w razie potrzeby ponowną transmisję ustalające kolejność odbieranych datagramów potwierdzające odbiór 5

sendto() - wysyłanie datagramu pobierając adres z odpowiedniej struktury SKŁADNIA int sendto(int sockfd, char *buff, int nbytes, int flags, struct sockaddr *to, int adrlen); OPIS Znaczenie argumentów: sockfd - deskryptor gniazda, buff - adres bufora zawierającego dane do wysłania, nbytes - liczba bajtów danych w buforze, flags- opcje sterowania transmisja lub opcje diagnostyczne, to - wskaźnik do struktury adresowej zawierającej adres punktu końcowego, do którego datagram ma być wysłany, adrlen - rozmiar struktury adresowej. Funkcja zwraca liczbę wysłanych bajtów, lub -1 w przypadku błędu. recvfrom() - odbieranie datagramu wraz z adresem nadawcy SKŁADNIA int recvfrom(int sockfd, char *buff, int nbytes, int flags, struct sockaddr *from, int *adrlen); OPIS Znaczenie argumentów: sockfd - deskryptor gniazda, buff - adres bufora, w którym zostaną umieszczone otrzymane dane, nbytes - liczba bajtów w buforze, flags- opcje sterowania transmisja lub opcje diagnostyczne, from - wskaźnik do struktury adresowej, w której zostanie wpisany adres nadawcy datagramu, adrlen - rozmiar struktury adresowej. Funkcja zwraca liczbę otrzymanych bajtów, lub -1 w przypadku błędu. 6

Przykład komunikacji z serwerem przez połączenie UDP #define BDL 120 /* dlugosc bufora char pytanie="czy jestes gotowy?"; /* tekst do przesłania char buf[bdl]; /* bufor na odpowiedź char bptr; /* wskaźnik do bufora int n; /* liczba przeczytanych bajtów int bufdl; /* ilość wolnego miejsca w buforze bptr=buf; bufdl=bdl; write(s,pytanie,strlen(pytanie)); n=read(gniazdo, bptr, bufdl); Wysyłanie danych do gniazda UDP Program użytkowy Bufor programu użytkowego sendto() proces użytkownika UDP bufor wysyłkowy gniazda jądro systemu IP datagram UDP pakiety IPv4 (MTU) Warstwa łącza Każde gniazdo UDP ma określony górny rozmiar datagramu UDP, który można przesyłać do gniazda (pełni funkcję podobną do bufora wysyłkowego TCP, ale UDP nie przechowuje kopii danych i nie ma potrzeby posiadania bufora wysyłkowego). Warstwa UDP umieszcza swój nagłówek i przesyła do warstwy UP. Oprogramowanie IP dołącza swój nagłówek i przesyła do warstwy łącza danych. 7

Przykład 1: Klient echa - czas oczekiwania na odpowiedź w kliencie zarządzany za pomocą sygnału SIGALRM #include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <signal.h> #define ECHOMAX 255 #define TIMEOUT 2 #define MAXPOWT 5 int powtorz=0; // liczba powtórzeń przesyłania void ObslugaBledu(char *kombledu); void PrzechwycAlarm(int ignoruj); // SIGALRM int main(int argc, char *argv[]) { int gniazdo; struct sockaddr_in SerwAdr; struct sockaddr_in Nadawca; unsigned short SerwPort; unsigned int rozmiarnad; struct sigaction obslugasyg; char *serwip; char *napis; char bufor[echomax+1]; int napisdl; int odpdl; if ((argc < 3) (argc > 4)) { fprintf(stderr,"uzycie: %s <Serwer IP> <Tekst> [<Port>]\n", argv[0]); exit(1); serwip = argv[1]; napis = argv[2]; if ((napisdl = strlen(napis)) > ECHOMAX) ObslugaBledu("Tekst za dlugi"); if (argc == 4) SerwPort = atoi(argv[3]); else SerwPort = 7; if ((gniazdo = socket(pf_inet, SOCK_DGRAM, IPPROTO_UDP)) < 0) ObslugaBledu("socket()"); obslugasyg.sa_handler = PrzechwycAlarm; if (sigfillset(&obslugasyg.sa_mask) < 0) ObslugaBledu("sigfillset()"); obslugasyg.sa_flags = 0; if (sigaction(sigalrm, &obslugasyg, 0) < 0) ObslugaBledu("sigaction() - SIGALRM"); 8

memset(&serwadr,0,sizeof(serwadr)); SerwAdr.sin_family = AF_INET; SerwAdr.sin_addr.s_addr=inet_addr(serwIP); SerwAdr.sin_port = htons(serwport); if (sendto(gniazdo,napis,napisdl,0, (struct sockaddr *) &SerwAdr, sizeof(serwadr))!= napisdl) ObslugaBledu("sendto() nie wyslal calego tekstu"); rozmiarnad = sizeof(nadawca); /* Ustaw budzik alarm(timeout); while ((odpdl = recvfrom(gniazdo, bufor, ECHOMAX, 0, (struct sockaddr *) &Nadawca, &rozmiarnad)) < 0) if (errno == EINTR) /* Upłynął czas!!! { if (liczbapowtorzen < MAXPOWT) { printf("czas uplynal, jeszcze %d proby.\n", MAXPOWT-powtorz); if (sendto(gniazdo, napis, napisdl, 0, (struct sockaddr *)&SerwAdr, sizeof(serwadr))!= napisdl) ObslugaBledu("sendto() failed"); /* Ustaw ponownie budzik alarm(timeout); else ObslugaBledu("Brak odpowiedzi"); else ObslugaBledu("recvfrom()"); /* Otrzymałem dane, wyłącz budzik alarm(0); bufor[odpdl] = '\0'; printf("otrzymano: %s\n", bufor); close(gniazdo); exit(0); void PrzechwycAlarm(int ignoruj) { liczbapowtorzen += 1; Zadanie: Sprawdź działanie programu. Zastąp funkcję obsługi sygnału sigaction() funkcją signal(). Czy program nadal działa w ten sam sposób? Jeśli nie, wyjaśnij powód. 9

4.3. Przykładowa biblioteka podstawowych funkcji dla programów klienckich Biblioteka zaproponowana w Comer, Stevens "Sieci komputerowe", tom 3. Podstawowe funkcje: utworzenie gniazda i nawiązanie połączenia socket = connecttcp(nazwa_komputera, usługa); socket = connectudp(nazwa_komputera, usługa); Implementacja funkcji connecttcp (plik connecttcp.c) /* *************************************************** * connecttcp nawiazanie lacznosci z serwerem * wskazanej uslugi TCP na wskazanym komputerze *************************************************** int connecttcp(const char *host, const char *service ) /* * Argumenty: * host - nazwa hosta, z którym chcemy się połaczyć * service - usługa związana z określonym portem { return connectsock( host, service, "tcp"); Implementacja funkcji connectudp (plik connectudp.c) /* *************************************************** * connectudp otwarcie gniazda komunikujacego sie * z serwerem wskazanej uslugi UDP na wskazanym * komputerze. *************************************************** int connectudp(const char *host, const char *service ) /* * Argumenty: * host - nazwa hosta, z którym chcemy się połaczyć * service - usługa związana z określonym portem { return connectsock(host, service, "udp"); 10

Implementacja funkcji connectsock (plik connectsock.c) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <string.h> #include <stdlib.h> #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* INADDR_NONE extern int errno; int errexit(const char *format,...); /*------------------------------------------------------------------------ * connectsock - utwórz i połącz gniazdo do komunikacji TCP lub UDP *------------------------------------------------------------------------ int connectsock(const char *host, const char *service, const char *transport ) /* * Argumenty: * host - nazwa hosta, z którym chcemy się połaczyć * service - usługa związana z określonym portem * transport - nazwa protokołu transportowego ("tcp" lub "udp") { struct hostent *phe; /* struktura opisująca komputer w sieci struct servent *pse; /* struktura opisująca usługę struct protoent *ppe; /* struktura opisująca protokół struct sockaddr_in sin; /* struktura adresowa int s, type; /* deskryptor gniazda, typ gniazda memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* Odwzoruj nazwę usługi na numer portu if ( pse = getservbyname(service, transport) ) sin.sin_port = pse->s_port; else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 ) errexit("can't get \"%s\" service entry\n", service); /* Odwzoruj adres w postaci nazwy lub zapisu kropkowo dziesiętnego na adres binarny IP if ( phe = gethostbyname(host) ) memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) errexit("can't get \"%s\" host entry\n", host); /* Odzworuj nazwę protokołu na jego numer if ( (ppe = getprotobyname(transport)) == 0) errexit("can't get \"%s\" protocol entry\n", transport); 11

/* Wybierz typ gniazda w zależności od protokołu if (strcmp(transport, "udp") == 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Przydziel gniazdo s = socket(pf_inet, type, ppe->p_proto); if (s < 0) errexit("can't create socket: %s\n", strerror(errno)); /* Połącz gniazdo if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) errexit("can't connect to %s.%s: %s\n", host, service, strerror(errno)); return s; Implementacja funkcji errexit (plik errexit.c) #include <stdarg.h> #include <stdio.h> #include <stdlib.h> /*------------------------------------------------------------------------ * errexit - print an error message and exit *------------------------------------------------------------------------ /* VARARGS1 int errexit(const char *format,...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); exit(1); Przykłady klientów TCP i UDP napisanych z użyciem proponowanej biblioteki: Comer, Stevens "Sieci komputerowe", tom 3 klient usługi DAYTIME, wersja TCP, str. 117-118 klient usługi TIME, wersja UDP, str-119-123 klient usługi ECHO, wersja TCP, str.123-125 klient usługi ECHO, wersja UDP, str. 125-126 12

Należy przeczytać: Douglas E. Comer, David L. Stevens: Sieci komputerowe TCP/IP, tom 3: str. 96-127 W. Richard Stevens: Unix, programowanie usług sieciowych, tom 1: API gniazda i XTI: str. 110-138, 248-272 13