Sieci komputerowe wykład 4.
Interfejs gniazd.
Gniazda TCP.
Gniazda (sockets) to abstrakcyjne mechanizmy umożliwiające wykonywanie systemowych funkcji wejścia – wyjścia w odniesieniu do sieci. Gniazda zostały zaprojektowane w Berkeley na potrzeby Unix BSD. Istnieje grupa funkcji systemowych obsługujących gniazda, funkcje te stanowią API (Application Program Interface).
Gniazda umożliwiają między innymi przesyłanie danych między procesami działającymi na komputerach w sieci z wykorzystaniem połączeń TCP lub protokołu UDP, przy czym same operacje wysyłania i odbierania danych przypominają zwykłe operacje zapisywania i odczytu z pliku.
Gniazdowe struktury adresowe.
W wielu funkcjach operujących na gniazdach należy podać wskaźnik do struktury adresowej. Dla różnych rodzin protokołów zdefiniowano różne struktury adresowe.
Dla Ipv4 struktura ta nazywa się sockaddr_in.
struct sockaddr_in {
uint8_t sin_len; // długość struktury (16)
sa_family_t sin_family; // rodzina adresow: AF_INET
u_int16_t sin_port; // nr portu w tzw. sieciowej kolejności // bajtów
struct in_addr sin_addr; // 32 bitowy adres IP w sieciowej // kolejności bajtów
char sin_zero[8] // nieużywane
};
Adres intrernetowy jest właściwie w strukturze:
struct in_addr {
u_int32_t s_addr; adres IP
W różnych systemach definicje mogą się różnić od powyższej. W linuxie sprobuj man 7 ip do wyswietlenia opisu.
Ogólna struktura adresowa gniazda (zdefiniowana w pliku nagłówkowym <sys/socket.h>:
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
Założono wykorzystywanie gniazd dla dowolnej rodziny protokołów obsługiwanej przez system operacyjny, dlatego funkcjom przekazuje się wskaźnik do odpowiedniej struktury rzutowany na sockaddr. Funkcje gniazd powstały przed wprowadzeniem do standardu ANSI C void *.
Funkcje przekształcania adresu: inet_aton(), inet_ntoa(), inet_pton(), inet_ntop().
int inet_aton(const char *strptr, struct in_addr *addrptr);
Przekształca adres w notacji „kropkowej” (np. „149.156.65.43”) zapisany jako napis w C na liczbę 32 bitową w sieciowej kolejności bajtów.
Funkcja inet_aton() zwraca 1 jeśli napis był poprawny, 0 jeśi wystąpił błąd.
char *inet_ntoa(struct in_addr inaddr);
Zwraca wskaźnik do napisu w notacji “kropkowej”.
Podobnie działają funkcje inet_pton(), inet_ntop() (patrz man).
Kolejność bajtów sieciowa i hosta.
Kolejności:
little endian - pierwszeństwo bajtu mniej znaczącego,
big endian – pierwszeństwo bajtu bardziej znaczącego.
Funkcje htons(), ntohs(), htonl(), ntohl().
(Host –to – Net, Net – to Host połączone z short lub long).
Serwer TCP
s=socket()
bind()
Klient TCP
dane
Przetwarzanie danych
write()
close(s)
read()
connect()
accept()
listen()
ustanowienie połączenia
oczekiwanie na ustanowienie połączenia z klientem
(trójfazowe uzgodnienie TCP)
znacznik końca pliku
Schemat typowej komunikacji między klientem a serwerem
w TCP dla serwera iteracyjnego.
Schemat działania serwera iteracyjnego:
s=socket();
connect();
bind(s,...);
listen(s,...);
while (1)
{
t=accept(s,...);
Obsluguj_klienta(t,…);
close(t);
}
Schemat działania serwera współbieżnego:
t=accept(s,...); // blokujące oczekiwanie na połączenie
if ( ! (pid=fork()) ){
close(s);
else close(t);
Przykładowy klient usługi whois.
/*Przyjmujemy arbitralny numer portu 51900 dla tej uslugi (standardowo w Unixie jest to 43) */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
main(int argc, char *argv[])
int s; // Deskryptor gniazda
int len; // Dlugosc odebranych danych (w bajtach)
struct sockaddr_in sa; /* Internetowa struktura adresu gniazda (IPv4)
Jej postac moze sie roznic w roznych systemach.
W linuxie sprobuj man 7 ip do wyswietlenia opisu.
Przykladowo:
sa_family_t sin_family; rodzina adresow: AF_INET
u_int16_t sin_port; nr portu
struct in_addr sin_addr;
Adres intrernetowy:
Typy: u_int16_t (16 bitowa liczba calkowita bez znaku)
u_int32_t (32 bitowa liczba calkowita bez znaku) sa
zdefiniowane w <sys/types.h>
Typ sa_family_t jest zdefiniowany w <sys/socket.h> */
struct hostent *hp; /* struktura przechowujaca informacje o komputerze:
nazwa, adresy IP. Definicja w netdb.h
Wskaznik do struktury jest zwracany np. przez
funkcje gethostbyname.
Sprawdz man gethostbyname dla opisu struktury
hostent i funkcji gethostbyname.
Przykladowo w linuxie:
struct hostent{
char * h_name; nazwa hosta
char ** h_aliases; lista aliasow
int h_addrtype; typ adresu
int h_length; dlugosc adresu
char ** h_addr_list; lista adresow IP
Uwaga! We wczesnych implementacjach zamiast
listy adresow IP byl pojedynczy adres
char * h_addr. Dla kompatybilnosci w netdb.h
dodaje sie #define h_addr h_addr_list
*/
char buf[BUFSIZ+1]; // Bufor
char *progname; // Podstawiamy wskaznik do nazwy programu (argv[0]
char *host; // Wskaznik do nazwy komputera odleglego
char *user; // Wskaznik do napisu okreslajacego nazwe konta
progname=argv[0];
// Sprawdz, czy program uruchomiono z dwoma argumentami
if(argc!=3){
fprintf(stderr,"Uzycie:%s maszyna uzytkownik\n",progname);
exit(1);
host=argv[1];
user=argv[2];
// Ustal adres (i inne dane)komputera odleglego. Funkcja zwraca wskaznik do
// struktury hostent (patrz wyzej)
if ((hp=gethostbyname(host))==NULL){
...
adanis