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

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

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

Gniazda BSD. komunikacja bezpołączeniowa

Programowanie sieciowe

Komunikacja sieciowa - interfejs gniazd

Iteracyjny serwer TCP i aplikacja UDP

Programowanie przy użyciu gniazdek

2. Interfejs gniazd Gniazdo

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

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

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

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

1. Model klient-serwer

Podstawowe typy serwerów

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

Programowanie Sieciowe 1

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

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

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

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

SUMA KONTROLNA (icmp_cksum) NUMER KOLEJNY (icmp_seq)

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Gniazda. S. Samolej: Gniazda 1

Klient-Serwer Komunikacja przy pomocy gniazd

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

Instytut Teleinformatyki

socket(int domain, int type, int protocol)

Oprogramowanie komunikacyjne dla Internetu rzeczy Laboratorium nr 4 komunikacja unicastowa IPv6

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

Architektura typu klient serwer: uproszczony klient POP3

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

Tryb bezpołączeniowy (datagramowy)

Gniazda BSD implementacja w C#

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

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

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

Aplikacja Sieciowa wątki po stronie klienta

Przykład aplikacji UDP

Serwer współbieżny połączeniowy

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

Krótkie wprowadzenie do korzystania z OpenSSL

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

Procesy. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 9 października 2011

Programowanie sieciowe

TIN Techniki Internetowe zima

Sygnały. 7. Sygnały (2005/2006)

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

1 Sposób zaliczenia przedmiotu

Łącza nienazwane(potoki)

iseries Programowanie z użyciem gniazd

Serwery współbieżne c.d.

Komunikacja za pomocą potoków. Tomasz Borzyszkowski

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Wstęp do Programowania, laboratorium 02

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

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

Programowanie Programowanie z użyciem gniazd

Programowanie współbieżne i rozproszone

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

Podstawowe typy serwerów

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

Programowanie Programowanie z użyciem gniazd

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

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

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

PROTOKOŁY WARSTWY TRANSPORTOWEJ

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

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Beej s Guide to Network Programming

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

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

2 Przygotował: mgr inż. Maciej Lasota

Projektowanie oprogramowania systemów KOMUNIKACJA SIECIOWA I SYSTEMY RPC

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

5. Algorytmy serwera

4.2 Sposób korzystania z l acza

Kolejki FIFO (łącza nazwane)

TRX API opis funkcji interfejsu

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

Temat zajęć: Obsługa łączy komunikacyjnych

INFORMATYKA Studia Niestacjonarne Elektrotechnika

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

Obsługa plików Procesy

Routing. część 1: adresowanie. Sieci komputerowe. Wykład 2. Marcin Bieńkowski

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

Programowanie Sieciowe 1

Pliki w C/C++ Przykłady na podstawie materiałów dr T. Jeleniewskiego

Funkcje zawarte w bibliotece < io.h >

Biblioteka standardowa - operacje wejścia/wyjścia

Pobieranie argumentów wiersza polecenia

Funkcje zawarte w bibliotece < io.h >

Podstawy programowania w języku C++

IPC: Kolejki komunikatów

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

Pliki. Informacje ogólne. Obsługa plików w języku C

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

Operacje na plikach. Informatyka. Standardowe strumienie wejścia i wyjścia

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

Program wykonujący operację na plikach powinien zachować schemat działania zapewniający poprawną pracę:

Transkrypt:

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_family_t char ; sa_len; sa_family; 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 listen() s=socket() accept() connect() write() ustanowienie połączenia (trójfazowe uzgodnienie TCP) dane oczekiwanie na read() Przetwarzanie danych dane write() read() close(s) znacznik końca pliku read() close(s)

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: s=socket(); connect(); bind(s,...); listen(s,...); while (1) t=accept(s,...); // blokujące oczekiwanie na połączenie if (! (pid=fork()) ) close(s); Obsluguj_klienta(t, ); close(t); 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: struct sockaddr_in sa_family_t sin_family; rodzina adresow: AF_INET u_int16_t sin_port; nr portu struct in_addr sin_addr; ; Adres intrernetowy: struct in_addr u_int32_t s_addr; adres IP ; 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);

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) fprintf(stderr,"%s: nie znalazlem komputera %s\n",progname,host); // Skopiuj adres IP z hp->h_addr do sa.sin_addr memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family=hp->h_addrtype; // Ustal numer portu. Htons powoduje zamiane na porzadek sieci sa.sin_port=htons(51900); // ntohs zamienia zapis liczby na porzadek hosta printf("\nport:%d\n",ntohs(sa.sin_port)); // Otworz gniazdo. Funkcja socket zwraca deskryptor gniazda // lub -1 w razie bledu. Sprawdz man socket. if((s=socket(hp->h_addrtype,sock_stream,0))<0) perror("socket"); // Podlacz gniazdo do serwera. Sprawdz man connect. // Standardowo wymaga rzutowania na typ wskazujacy na // strukture struct sockaddr if(connect(s,(struct sockaddr *) &sa, sizeof(sa))<0) perror("connect"); // Wyslij zapytanie do serwera. Jesli nie uda sie wyslac // do gniazda tylu bajtow ile wynosi dlugosc napisu *user // to blad zapisu. if (write(s,user,strlen(user))!= strlen(user)) fprintf(stderr, "%s: blad zapisu",progname); // Dopoki serwer nie zakonczyl pisania czytaj dane do bufora. // Odpowiedz serwera moze dojsc "w kawalkach". // Deskryptor pliku 1 uzyty w funkcji write oznacza // standardowe wyjscie. while ((len=read(s,buf,bufsiz))>0) write(1,buf,len); // Zamknij gniazdo close(s); // Zakoncz z kodem bledu 0 exit(0); Przykładowy serwer usługi whois.

/* Przyjeto arbitralny numer portu 51900 (standardowo w Unixie jest to 43). Serwer obsluguje jednoczesnie jednego klienta. Ewentualne odwolania innych klientow ustawiane sa w kolejce o dlugosci zdefiniowanej przez DL_KOLEJKI*/ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <pwd.h> #define DL_KOLEJKI 5 #define MAXHOSTNAME 32 int main(int argc, char * argv[]) int s,t; // Deskryptory gniazd int i; // Zmienna robocza struct sockaddr_in sa, isa; // Internetowa struktura adresowa gniazda // Opis w programie klient struct hostent *hp; // Struktura przechowujaca dane o komputerze // Opis w programie klient char *progname; // wskaznik do nazwy programu char localhost[maxhostname+1];// nazwa lokalnego komputera jako napis progname=argv[0]; // Odczytaj nazwe komputera lokalnego gethostname(localhost,maxhostname); // Odczytaj dane o kpmputerze lokalnym (m.in. numer IP) if((hp=gethostbyname(localhost))==null) fprintf(stderr, "%s: Nie znalazlem komputera %s\n", progname); // Ustal numer portu sa.sin_port = htons(1900); // Skopiuj adres IP z hp->h_addr do sa.sin_addr memcpy(&sa.sin_addr,hp->h_addr, hp->h_length); //Mozna to zrobic inaczej: //bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length); sa.sin_family=hp->h_addrtype; // Otworz gniazdo. Funkcja socket zwraca deskryptor gniazda // lub -1 w razie bledu. Sprawdz man socket. if ((s=socket(hp->h_addrtype, SOCK_STREAM,0))<0) perror("socket"); // Zwiaz gniazdo z numerem IP i numerem portu (przypisanie // lokalnego adresu protokolowego. Wymaga rzutowania drugiego // argumentu na wskaznik do struktury struct sockaddr. Zwraca // zero jesli wszystko ok, -1 w przeciwnym wypadku. if ( ( bind(s,(struct sockaddr *) &sa,sizeof(sa))<0)) perror("bind"); // Ustaw gniazdo w stan nasluchiwania (gniazdo bierne)

// i ustal maksymalna liczbe polaczen, ktore jadro systemu powinno // ustawic w kolejce do tego gniazda (DL_KOLEJKI) listen(s,dl_kolejki); // Wejdz w nieskonczona petle w oczekiwaniu na polaczenia. while(1) i=sizeof isa; // Zawieszenie na funkcji accept w oczekiwaniu na klientow // (uspienie procesu). Patrz man 2 accept. Funkcja accept tworzy // nowe gniazdo dla polaczenia z klientem i obslugi klienta. // Gniazdo nasluchujace dalej sluzy tylko do nasluchu. if((t=accept(s,(struct sockaddr *) &isa,&i))<0) perror("accept"); whois(t); // Wykonanie uslugi whois (patrz nizej) close(t); whois(int sock) struct passwd *p; passwd // Patrz man getpwnam. char buf[bufsiz+1]; int i; // Odczytaj zapytanie od klienta if ((i=read(sock,buf,bufsiz))<=0) return; // Zakoncz napis standardowym znakiem \0 buf[i]='\0'; // struktura przechowujaca dane z linijki w /etc/ // getpwnam zwraca wskaznik do struktury zawierajacej // pola linijki z /etc/passwd, ktˇra odpowiada // uzytkownikowi o nazwie przekazanej jako parametr. if((p=getpwnam(buf))==null) strcpy(buf,"nie ma takiego uzytkownika\n"); else sprintf(buf,"%s: %s\n",p->pw_name, p->pw_gecos); // Wpisz bufor do gniazda (wyslij dane do klienta) write(sock,buf,strlen(buf)); return;

Ważne zagadnienia objaśniane na podstawie przykładowych programów. Działanie funkcji fork(). Obsługa sygnałów. Sygnał jest informacją dla procesu, że wystąpiło jakieś zdarzenie. Sygnały nazywane są też przerwaniami programowymi. Sygnały są na ogół wysyłane asynchronicznie. Sygnały są wysyłane z procesu do procesu (również siebie samego) oraz z jądra do procesu. Gdy kończy się proces potomny, wówczas jądro systemu przesyła do procesu macierzystego sygnał SIGCHLD. Proces potomny staje się zombie (defunct), umożliwiając procesowi macierzystemu pobranie informacji o rozmiarach zasobów użytych przez proces potomny. Aby nie był tworzony zombie należy wywołać funkcję wait() w funkcji obsługującej sygnał SIGCHLD. signal(sigchld, sig_chld);. void sig_chld(int signo) pid_t pid; int stat; pid = wait(&stat); return; Takie rozwiązanie może się jednak zakończyć przerwaniem wykonywania programu (procesu macierzystego), jeśli sygnał nadszedł w momencie blokowania na funkcji accept(). Nie we wszystkich systemach jądro wznawia przerwane funkcje systemowe. Funkcja może być zakończona z kodem błędu EINTR. Zatem należy dodać obsługę tego błedu, np. if ( t = accept() < 0) if (errno == EINTR) continue; // powrót do pętli, w której wywoływana jest f. accept(); else perror( accept ); Najprostszy sposób (niestety nie działający we wszystkich systemach) na uniknięcie kłopotów to zlecenie ignorowania sygnału SIGCHLD. Robi się to z użyciem funkcji signal(): signal(sigchld, SIG_IGN);

Gniazda UDP. Serwer UDP s=socket() Klient UDP bind() s=socket() recvfrom() sendto() dane oczekiwanie na nadejście danych od dowolnego klienta Przetwarzanie danych dane sendto() recvfrom() close(s) Schemat typowej komunikacji między klientem a serwerem w UDP. Przypisanie numeru portu lokalnego (efemerycznego) następuje przy pierwszym wywołaniu funkcji sendto().

Klient nie ustanawia połączenia z serwerem, jedynie wysyła datagramy. Serwer odbiera datagramy od dowolnych klientów. Funkcje recfrom() zwraca adres klienta, zatem serwer może przesłać odpowiedź.

#include <sys/socket.h> ssize_t recvfrom(int socket, void *buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen); ssize_t sendto(int socket, const void *buff, size_t nbytes, int flags, const struct sockaddr *to, socklen_t addrlen); Funkcje te zwracają liczbę odesłanych albo pobranych bajtów lub 1 jeśli wystąpił błąd. Przykładowy klient UDP klient echa. #include <unp.h> #define MAXLINE... int main (int argc, char ** argv) int s; struct sockaddr_in servaddr; int n; char sendbuff[maxline], recvbuff[maxline+1]; if ( argc!= 2) printf( Uzycie: klient adresip ); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons( 51000 ); // wstawienie numeru IP do servaddr inet_pton ( AF_INET, argv[1], &servaddr.sin_addr); s = socket (AF_INET, SOCK_DGRAM, 0); if (p < 0 ) perror("socket"); // fgets wczytuje linię ze standardowego wejścia // fputs wypisuje linię na standardowe wyjście while (fgets (sendbuff, MAXLINE, stdin)!= NULL) sendto(s, sendbuff, strlen(sendbuff),0,&servaddr, sizeof(servaddr)); /* Poniżej NULL oznacza, że klient odbiera odpowiedź od dowolnego serwera */ n = recvfrom(s, recvbuff, MAXLINE, 0, NULL, NULL); recvbuff[n] = 0; // zakończenie napisu fputs(recvbuff, stdout);

Fragment klient echa wersja z zarządzaniem czasem oczekiwania przez sygnał SIGALRM.... // ustanowienie procedury obslugi sygnalu SIGALRM signal(sigalrm, sig_alrm); while (fgets (sendbuff, MAXLINE, stdin)!= NULL) sendto(s, sendbuff, strlen(sendbuff),0,&servaddr, sizeof (servaddr)); // ustawienie 5-cio sekundowego czasu oczekiwania alarm(5); /* Poniżej NULL oznacza, że klient odbiera odpowiedź od dowolnego serwera */ n = recvfrom(s, recvbuff, MAXLINE, 0, NULL, NULL); if (n < 0) if (errno == EINTR) fprintf(stderr, Przekroczony czas oczekiwania\n ); else perror( Blad gniazda ); else alarm(0); recvbuff[n] = 0; // zakończenie napisu fputs(recvbuff, stdout); // Procedura obslugi sygnalu SIGALRM void sig_alrm( int signo ) // Tylko przerywamy wykonywanie funkcji recvfrom() return; Przykładowy serwer UDP serwer echa. #include <unp.h> int main (int argc, char ** argv) int s; struct sockaddr_in servaddr, cliaddr; int n; int len; char buf[maxline]; s = socket(af_inet, SOCK_DGRAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(inaddr_any); servaddr.sin_port = htons(51000); bind(s, (sockaddr *) &servaddr, sizeof(servaddr)); for ( ; ; ) n = recvfrom(s, buf, MAXLINE, 0, &cliaddr, &len); sendto(s, buf, n, 0, cliaddr, len);

Większość serwerów UDP to serwery iteracyjne. Można jednak tworzyć współbieżne (patrz Stevens). Gniazda UDP niepołączone i połączone. Gniazdo niepołączone to takie, jak powyżej. Gniazdo połączone powstaje w wyniku wywołania funkcji connect() dla gniazda UDP. Dla gniazda połączonego: 1) Dla operacji wyjścia adres docelowy jest już zapamiętany i nie można go zmienić. W szczególności zamiast funkcji sendto() należy używać write() (lub send). 2) Podobnie nie stosuje się funkcji recvfrom(), tylko read(). Literatura: W.R. Stevens: Unix programowanie usług sieciowych, tom 1, API: gniazda. WNT, Warszawa 2000.