riassunto reti di calcolatori

61
1 Prof. Roberto De Prisco Reti di Calcolatori Corso di laurea in Informatica A.A. 2007-2008 Lezione LABORATORIO 1 1 1 LABORATORIO LABORATORIO LABORATORIO LABORATORIO Autunno 2007 Autunno 2007 Autunno 2007 Autunno 2007 2 2 2 Obiettivo Saper scrivere semplici programmi per la comunicazione su una rete di calcolatori Assunzione Sapete già programmare … Ambiente di sviluppo LINUX Compilatore C Socket per la comunicazione in rete

description

riassunto di reti di calcolatori

Transcript of riassunto reti di calcolatori

  • 1Prof. Roberto De Prisco

    Reti di Calcolatori

    Corso di laurea in Informatica

    A.A. 2007-2008

    Lezione

    LABORATORIO

    1111

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    2222Obiettivo

    Saper scrivere semplici programmi per la comunicazione su una rete di calcolatori

    Assunzione Sapete gi programmare

    Ambiente di sviluppo LINUX Compilatore C Socket per la comunicazione in rete

  • 2LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    3333Desktop grafico

    Desktop grafico

    Usare solo per scaricare gli esempi

    Terminale testuale

    CTRL-ALT-F1

    CTRL-ALT-F6

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    4444Linea di comando

    Terminale testuale Line di comando Prompt

    Comandi ls, cd, pwd, cp, rm, mv, cat, mkdir man

    robdep@zircone:~/Corsi/Reti/C> gmakegcc -g -O0 -Werror -c lib-errori.cgcc -g -O0 -Werror -c lib-corso-reti.ccompiling daytimesrv.c with rule 1

    robdep@zircone:~/Corsi/Reti/C>

  • 3LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    5555Shell

    Shell il programma che interpreta i comandi

    BASH la shell standard di Linux Echo $SHELL

    Sezione risorse del Sito web Link a pagine su Bash e altro (es. editor vi)

    Sito Web del corso LSO

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    6666File

    Editor di file vi emacs

    Occorre imparare ad usare uno di questi due editor Basta il minimo indispensabile

    Manuali Una ricerca su Internet vi fornir numerosi fonti manuale editor vi

  • 4LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    7777Programmi in C#include #include #include #include int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {

    union {union {union {union {short s;short s;short s;short s;char c[sizeof(short)];char c[sizeof(short)];char c[sizeof(short)];char c[sizeof(short)];

    } un;} un;} un;} un;un.s = 0x0102;un.s = 0x0102;un.s = 0x0102;un.s = 0x0102;printf("CPU = %s printf("CPU = %s printf("CPU = %s printf("CPU = %s ---- byte ordering: ",getenv("CPU"));byte ordering: ",getenv("CPU"));byte ordering: ",getenv("CPU"));byte ordering: ",getenv("CPU"));if (sizeof(short) == 2) {if (sizeof(short) == 2) {if (sizeof(short) == 2) {if (sizeof(short) == 2) {

    if ( un.c[0] == 1 && un.c[1] == 2 ) if ( un.c[0] == 1 && un.c[1] == 2 ) if ( un.c[0] == 1 && un.c[1] == 2 ) if ( un.c[0] == 1 && un.c[1] == 2 ) printf ("bigprintf ("bigprintf ("bigprintf ("big----endianendianendianendian\\\\n");n");n");n");

    else if ( un.c[0] == 2 && un.c[1] == 1 ) else if ( un.c[0] == 2 && un.c[1] == 1 ) else if ( un.c[0] == 2 && un.c[1] == 1 ) else if ( un.c[0] == 2 && un.c[1] == 1 ) printf ("littleprintf ("littleprintf ("littleprintf ("little----endianendianendianendian\\\\n");n");n");n");

    elseelseelseelseprintf("unknownprintf("unknownprintf("unknownprintf("unknown\\\\n");n");n");n");

    }}}}elseelseelseelse

    printf("size of short: %d.printf("size of short: %d.printf("size of short: %d.printf("size of short: %d.\\\\n",sizeof(short));n",sizeof(short));n",sizeof(short));n",sizeof(short));exit(0);exit(0);exit(0);exit(0);

    }}}}

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    8888Compilazione e Makefile

    Il sorgente C va compilato

    Compilare un programma consiste nel1.trasformare il sorgente C in codice oggetto2.unire tale codice oggetto con le librerie (link)

    gcc (GNU C Compiler) gcc ls1.c gcc o ls1 ls1.c gcc Lmylibpath lmylib Imyincpath O DDEBUG ...

    Makefile make ... fa tutto

  • 5LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    9999Makefile

    #Makefile

    ALL = lib-errori lib-corso-reti \

    daytimesrv daytimecli daytimesrv-ric \

    echosrv echocli echosrv-sigh

    all: $(ALL)

    .c: lib-errori.o lib-corso-reti.o

    @echo compiling $< with rule 1

    gcc $< -g -O0 Werror -o $@ lib-errori.o lib-corso-reti.o

    lib-errori: lib-errori.c

    gcc -g -O0 -Werror -c lib-errori.c

    lib-corso-reti: lib-corso-reti.c

    gcc -g -O0 -Werror -c lib-corso-reti.c

    clean:

    rm -f $(ALL)

    rm -f *~

    rm -f *.o

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    10101010Esempio

    robdep@zircone:~/Corsi/Reti/C> gmakegcc -g -O0 -Werror -c lib-errori.cgcc -g -O0 -Werror -c lib-corso-reti.ccompiling daytimesrv.c with rule 1gcc daytimesrv.c -g -O0 -Werror -o daytimesrv lib-errori.o lib-corso-reti.ocompiling daytimecli.c with rule 1gcc daytimecli.c -g -O0 -Werror -o daytimecli lib-errori.o lib-corso-reti.ocompiling daytimesrv-ric.c with rule 1gcc daytimesrv-ric.c -g -O0 -Werror -o daytimesrv-ric lib-errori.o lib-corso-reti.ocompiling echosrv.c with rule 1gcc echosrv.c -g -O0 -Werror -o echosrv lib-errori.o lib-corso-reti.o

  • 6LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    11111111Librerie e include file

    #include Cerca il file da includere nelle directory di ricerca

    standard del compilatore /usr/include, /usr/lib/include, ...

    # include nome.h Cerca il file da includere nella cwd

    Al momento di eseguire il link il compilatore cerca il codice necessario nelle librerie librerie specificate con l nel comando di compilazione la ricerca di tali librerie fatta in posti standard (/usr/lib,

    /usr/local/lib, ...) e nelle directory specificate con L libreria di default (contiene printf)

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    12121212Basic.h

    #ifndef __BASIC__

    #define __BASIC__

    #include /* basic system data types */

    #include /* basic socket definitions */

    #include /* timeval{} for select() */

    #include /* timespec{} for pselect() */

    #include /* sockaddr_in{} and other Internet defns */

    #include /* inet(3) functions */

    #include

    #include

    #include

    #include /* for Unix domain sockets */

    #define MAXLINE 256

    #define PORT 12345

    #define BACKLOG 5

    #define MAX(a, b) ((a) > (b) ? (a) : (b))

    #endif

  • 7LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    13131313Libreria gestioni errori

    Definisce varie funzioni per la gestione degli errori

    Facciamo il link con questa libreria per usare tali funzioni

    Sono funzioni che stampano un messaggio di errore Alcune terminano lesecuzione del programma

    File lib-errori.c err_msg stampa solo lerrore err_quit, err_sys chiamano exit

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    14141414Libreria corso reti

    Definisce varie funzioni per la lettura e scrittura dei socket

    Convezione sul nome reti_nomefunzione

    Esempi di funzioni della libreria reti_readn

    Legge esattamente n byte reti_writen

    Scrive esattamente n byte reti_readline

    Legge una riga

    Dettagli nel file lib-corso-reti.c

  • 8Prof. Roberto De Prisco

    Reti di Calcolatori

    Corso di laurea in Informatica

    A.A. 2007-2008

    Lezione

    Socket TCP

    2222

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    16161616Socket

    Letteralmente significa presa (di corrente)

    lastrazione di un canale di comunicazione fra due computer connessi da una rete

    Sono definiti per vari protocolli

    Per TCP/IP un socket identifica i due punti della connessione Un indirizzo IP ed una porta su un host Un indirizzo IP ed una porta sullaltro host

  • 9LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    17171717Funzioni per i socket

    socket()

    bind()

    listen()

    accept()socket()

    connect()

    write()

    read()

    read()

    write()

    read()

    close()

    close()

    Aspetta una connessione

    Stabilisce una connessione

    Dati (richiesta)

    Notificazione di fine comunicazione

    Dati (risposta)

    CLIENT

    CLIENT

    CLIENT

    CLIENT

    SERVER

    SERVER

    SERVER

    SERVER

    Tipica interazione in una connessione TCP

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    18181818Sockaddr_in

    struct in_addr {

    in_addr_t s_addr; /* 32-bit, network byte ordered */

    }

    struct sockaddr_in {

    uint8_t sin_len;

    sa_family_t sin_family; /* tipo di protocollo, AF_INET */

    in_port_t sin_port; /* 16-bit, network byte ordered */

    struct in_addr sin_addr; /* struttura indirizzo IP */

    char sin_zero[8];

    }

    struct sockaddr {

    uint8_t sin_len;

    sa_family_t sin_family; /* tipo di protocollo: AF_XXX */

    char sa_data[14]; /* indirizzo specifico del protocollo */

    }

    sin_zero Utilizzata per far si che la grandezza della struttura sia almeno 16 byte

    sin_len Non richiesta dallo standard Posix Esistono diverse strutture con grandezze differenti

  • 10

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    19191919Lunghezze strutture socket

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    20202020Funzione socket

    #include int socket(int family, int type, int protocol );

    Valore di ritorno: -1 se erroreun socket descriptor se OK

    Socket descriptor come un file descriptor Sono presi dallo stesso insieme Se un intero usato come file descriptor non pu

    essere usato come socket descriptor e viceversa Socket e file sono visti pi o meno allo stesso modo

    read, write, close sono le stesse funzioni dei file

  • 11

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    21212121Funzione socket

    int family Un intero che specifica quale famiglia di protocolli si

    intende usare: AF_INET IPv4 AF_INET6 IPv6 AF_LOCAL prot. locale (client e server sullo stesso host) AF_ROUTE Sockets per routing altri

    int type Un intero che dice il tipo di socket

    SOCK_STREAM per uno stream di dati (TCP) SOCK_DGRAM per datagrammi (UDP) SOCK_RAW per applicazioni dirette su IP

    int protocol 0, tranne che per SOCK_RAW

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    22222222Funzione connect

    #include int connect(int sd, struct sockaddr *servaddr, socklen_t addrlen);

    Valore di ritorno: -1 se errore, 0 se OK

    Permette ad un client di aprire una connessione con il server

    Il kernel sceglie una porta effimera (e lindirizzo IP)

    Nel caso di una connessione TCP viene fatto lhandshaking, in caso di errore ritorna (errno) ETIMEDOUT ECONNREFUSED EHOSTUNREACH

  • 12

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    23232323Funzione bind#include int bind(int sd, struct sockaddr*myaddr, socklen_t addrlen);

    Valore di ritorno: -1 se errore, 0 se OK

    Permette ad un server di assegnare un indirizzo per il server al socket

    Con TCP lindirizzo pu essere indirizzo IP (deve essere una delle interfacce) porta entrambi nessuno

    Se la porta non specificata (valore 0) ne viene scelta una effimera

    Se lindirizzo IP quello wildcard (INADDR_ANY, 0) viene usato quello designato come IP destinazione nel SYN del client

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    24242424Funzione listen

    #include int listen(int sd, int backlog);

    Valore di ritorno: -1 se errore, 0 se OK

    Usata solo da un server TCP, serve a

    1. Convertire il socket da attivo a passivo, per far s che il kernel accetti connessioni sul socket Per default un socket creato attivo, e il kernel si aspetta che sia

    il socket di un client Nel diagramma a stati TCP fa muovere da CLOSED a LISTEN

    2. Backlog specifica quante connessioni accettare e mettere in attesa per essere servite

  • 13

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    25252525Backlog

    La somma degli elementi in entrambe le code non pu superare il backlog

    ServerServerServerServer acceptacceptacceptaccept

    connect dal clientconnect dal clientconnect dal clientconnect dal client

    SYN apertura connessione

    apertura conn. completata

    CODA connessioni completate

    (stato ESTABLISHED)

    CODA connessioni incomplete

    (stato SYN_RCVD)

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    26262626Funzione accept

    #include int accept(int sd, struct sockaddr*cliaddr, socklen_t addrlen);

    Valore di ritorno: -1 se errore, socked descriptor se OK

    Permette ad un server di prendere la prima connessione completata dalla coda Se non ce ne sono si blocca

    cliaddr un parametro valore-risultato In chiamata contiene il listening socket Al ritorno contiene il socket connesso al particolare

    client

  • 14

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    27272727Daytime server

    #include "basic.h#include int main(int argc, char **argv) {

    pid_t pid;int listenfd, connfd;struct sockaddr_in servaddr;char buff[MAXLINE];time_t ticks;if (argc != 2) err_quit("usage: daytimesrv ");if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)

    err_sys("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(atoi(argv[1]));if( (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) < 0)

    err_sys("bind error");if( listen(listenfd, 5) < 0 ) err_sys("listen error");for ( ; ; ) {

    if( (connfd = accept(listenfd, (struct sockaddr *) NULL, NULL)) < 0)

    err_sys("accept error");ticks = time(NULL);snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));write(connfd, buff, strlen(buff));close(connfd);

    }}

    daytimesrv.c

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    28282828Server iterativo

    Server iterativo, serve i client uno alla volta

    Quando un client connesso il seguente client deve aspettare

    Accettabile per server semplici come il daytime

  • 15

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    29292929Funzione inet_pton

    #include int inet_pton(int af, const char* stringa, void* dest);

    Valore di ritorno: 0 se errore, > 0 se OK

    Trasforma un indirizzo IP da formato presentazione a formato network

    Presentazione: stringa 192.41.218.1

    Network: sequenza di bit 11000000.00101001.110011010.00000001

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    30303030Daytime client

    #include "basic.h"int main(int argc, char **argv) {

    int sockfd, n;char recvline[MAXLINE + 1];struct sockaddr_in servaddr;

    if (argc != 3) err_quit("usage: daytimecli ");if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )

    err_sys("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(atoi(argv[2]));

    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) 0) {recvline[n] = 0; /* 0 finale richiesto dal C per le stringhe */fputs(recvline, stdout);

    }exit(0);

    }

    daytimecli.cdaytimecli.cdaytimecli.cdaytimecli.c

  • 16

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    31313131Server ricorsivi

    Un server ricorsivo usa una copia di se stesso per servire una richiesta

    pid_t pid;int listenfd, connfd;

    listenfd = socket(.);

    /* riempi la struttura sockaddr_in (es. numero di porta) */

    bind(listenfd,.)listen(listenfd, LISTENQ)

    for ( ; ; ) {connfd = accept(listenfd,);if ( (pid = fork()) == 0) {

    close(listenfd); /* figlio chiude il socket di ascolto */DOIT(connfd); /* serve la richiesta */close(connfd); /* chiude il socket */exit(0); /* il figlio termina */

    }close(connfd); /* il padre chiude il socket della connessione */

    }

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    32323232Server iterativi

    connect()connect()connect()connect()

    listensdlistensdlistensdlistensd

    Richiesta di connessioneRichiesta di connessioneRichiesta di connessioneRichiesta di connessione

    connect()connect()connect()connect()

    listensdlistensdlistensdlistensd

    Connessione stabilitaConnessione stabilitaConnessione stabilitaConnessione stabilita connsdconnsdconnsdconnsd

    Il server chiama accept()

    Viene creato un nuovo socket descriptor nel server per la connessione con questo particolare client

    ClientClientClientClient ServerServerServerServer

    ClientClientClientClient ServerServerServerServer

  • 17

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    33333333Server ricorsivi

    connect()connect()connect()connect()

    listensdlistensdlistensdlistensd

    Connessione stabilitaConnessione stabilitaConnessione stabilitaConnessione stabilita

    connsdconnsdconnsdconnsd

    Il server chiama fork()

    Padre e figlio nel server condividono il socket

    ClientClientClientClient ServerServerServerServer

    listensdlistensdlistensdlistensd

    connsdconnsdconnsdconnsd

    ServerServerServerServer

    padrepadrepadrepadre

    figliofigliofigliofiglio

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    34343434Server ricorsivi

    connect()connect()connect()connect()

    listensdlistensdlistensdlistensd

    Connessione stabilitaConnessione stabilitaConnessione stabilitaConnessione stabilita

    connsdconnsdconnsdconnsd

    Il padre chiude il socket della connessione Pu accettare nuove connessioni

    Il figlio chiude il socket per laccettazione di nuove connessioni Pu gestire la connessione con il client

    ClientClientClientClient ServerServerServerServer

    listensdlistensdlistensdlistensd

    connsdconnsdconnsdconnsd

    ServerServerServerServer

    padrepadrepadrepadre

    figliofigliofigliofiglio

  • 18

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    35353535Getsockname e getpeername#include int getsockname(int sd, struct sockaddr*localaddr, socklen_t addrlen);int getpeername(int sd, struct sockaddr*remoteaddr, socklen_t addrlen);

    Valore di ritorno: -1 se errore, socked descriptor se OK

    Ritornano lindirizzo locale associato al socket Lindirizzo dellaltro lato della connessione associata al socket

    Serve perch Un client che non chiama bind non sa quale porta stata usata Un client non sa lindirizzo IP usato se ci sono pi interfaccie Una chiamata a bind con porta=0 assegna una porta effimera Stessa cosa per lindirizzo IP (INADDR_ANY) Dopo una exec si pu risalire agli indirizzi della connessione

    NB: un file descriptor rimane aperto quando si chiama exec

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    36363636Echo server (1)

    #include "basic.h"#include "echo.h"

    int main(int argc, char **argv) {pid_t childpid;int listenfd, connfd;struct sockaddr_in servaddr, cliaddr;socklen_t cliaddr_len;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT); /* daytime server */

    if( (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) < 0)err_sys("bind error");

    if( listen(listenfd, LISTENQ) < 0 )err_sys("listen error");

    echosrv.cechosrv.cechosrv.cechosrv.c

  • 19

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    37373737Echo server (2)

    for ( ; ; ) {cliaddr_len = sizeof(cliaddr);if( (connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &cliaddr_len)) < 0)

    err_sys("accept error");

    if( (childpid = fork()) == 0 ) {close(listenfd);str_echo(connfd);exit(0);

    }close(connfd);

    }}

    void str_echo(int sockfd) {ssize_t n;char line[MAXLINE];for ( ; ; ) {

    if ( (n = read(sockfd, line, MAXLINE)) == 0)return; /* connection closed by other end */

    write(sockfd, line, n);}

    }

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    38383838Echo client (1)

    #include "basic.h"#include "echo.h"int main(int argc, char **argv) {

    int sockfd, n;struct sockaddr_in servaddr;

    if (argc != 2)err_quit("usage: echotcpcli ");

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT); /* echo server */if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr)

  • 20

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    39393939Echo client (2)

    void str_cli(FILE *fp, int sockfd) {char sendline[MAXLINE], recvline[MAXLINE];while (fgets(sendline, MAXLINE, fp) != NULL) {

    reti_writen(sockfd, sendline, strlen(sendline));if (reti_readline(sockfd, recvline, MAXLINE) == 0)

    err_quit("str_cli: server terminated prematurely");fputs(recvline, stdout);

    }}

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    40404040Echo server

    prompt > echoserver &prompt > echoserver &prompt > echoserver &prompt > echoserver &

    [1] 21130 [1] 21130 [1] 21130 [1] 21130

    prompt > netstat prompt > netstat prompt > netstat prompt > netstat aaaa

    Proto RecvProto RecvProto RecvProto Recv----Q SendQ SendQ SendQ Send----Q Local address Foreign address (state)Q Local address Foreign address (state)Q Local address Foreign address (state)Q Local address Foreign address (state)

    TcpTcpTcpTcp 0000 0 *.98770 *.98770 *.98770 *.9877 *.**.**.**.*

    LISTENLISTENLISTENLISTEN

    prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1

    Per semplicit facciamo girare server e client sulla stessa macchina

    A questo punto la connessione stabilita

    prompt > netstat prompt > netstat prompt > netstat prompt > netstat aaaa

    Proto RecvProto RecvProto RecvProto Recv----Q SendQ SendQ SendQ Send----Q Local address Foreign addressQ Local address Foreign addressQ Local address Foreign addressQ Local address Foreign address (state)(state)(state)(state)

    TcpTcpTcpTcp 0000 0 localhost.9877 localhost.1052 0 localhost.9877 localhost.1052 0 localhost.9877 localhost.1052 0 localhost.9877 localhost.1052 ESTABLISHEDESTABLISHEDESTABLISHEDESTABLISHED

    TcpTcpTcpTcp 0000 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 ESTABLISHEDESTABLISHEDESTABLISHEDESTABLISHED

    TcpTcpTcpTcp 0000 0 *.98770 *.98770 *.98770 *.9877 *.**.**.**.* LISTENLISTENLISTENLISTEN

    In unaltra finestra

  • 21

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    41414141Echo server

    Il server ha chiuso il socket Il client nello stato di TIME_WAIT

    Il lato che chiude la connessione rimane in questo stato per un certo periodo (2MSL) per1. Mantenere informazioni nel caso lultimo ACK viene perso e laltro lato

    rispedisce lultimo FIN2. Permettere a vecchi pacchetti di essere eliminati dalla rete in modo da non

    farli interferire con successive connessioni

    prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1

    Ciao serverCiao serverCiao serverCiao server

    Ciao serverCiao serverCiao serverCiao server

    ArrivederciArrivederciArrivederciArrivederci

    ArrivederciArrivederciArrivederciArrivederci

    ^D^D^D^D

    prompt >prompt >prompt >prompt >

    prompt > netstat prompt > netstat prompt > netstat prompt > netstat a | grep 9877a | grep 9877a | grep 9877a | grep 9877

    TcpTcpTcpTcp 0000 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 0 localhost.1052 localhost.9877 TIME_WAITTIME_WAITTIME_WAITTIME_WAIT

    TcpTcpTcpTcp 0000 0 *.98770 *.98770 *.98770 *.9877 *.**.**.**.* LISTENLISTENLISTENLISTEN

    Digitata al terminaleDigitata al terminaleDigitata al terminaleDigitata al terminaleRisposta del serverRisposta del serverRisposta del serverRisposta del server

    Digitata al terminaleDigitata al terminaleDigitata al terminaleDigitata al terminaleRisposta del serverRisposta del serverRisposta del serverRisposta del server

    Digitata al terminaleDigitata al terminaleDigitata al terminaleDigitata al terminale

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    42424242Echo server

    Digitando ^D, il client termina chiamando exit Il kernel chiude tutti i file descriptor, quindi anche i socket descriptor Quindi il socket del client viene chiuso La chiusura implica

    la spedizione di FIN al server La ricezione dellACK al FIN

    A questo punto il server nello stato CLOSE_WAIT mentre il client nello stato FIN_WAIT_2

    La prima parte della chiusura di una connessione TCP conclusa

    Quando il server riceve il FIN nella readline che ritorna EOF e quindi chiama exit

    I file descriptor vengono chiusi, quindi anche il socket ed un FIN viene spedito al client

    A questo punto la conessione completamente terminata ed il client va nello stato TIME_WAIT mentre il server ha chiuso la connessione

    Dopo un certo periodo (2 Maximum Segment Lifetime) il client chiude la connessione

  • 22

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    43434343Segnale SIGCHLD

    In un server ricorsivo, il server crea un figlio per gestire la connessione

    quando la connessione viene chiusa il figlio termina

    Il sistema operativo manda un segnale di SIGCHLD al padre e il figlio diventa zombie Zombie sono dei processi terminati per i quali

    vengono mantenuti dei dati nel sistema operativo Zombie sono necessari per permettere al padre di

    controllare il valore di uscita del processo e utilizzo delle risorse del figlio (memoria, CPU, etc.)

    Ovviamente non vogliamo lasciare zombie Occorre scrivere un signal handler che chiama

    wait

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    44444444zombie

    robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1

    ciaociaociaociao

    ciao ciao ciao ciao

    ^D^D^D^D

    robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1robdep@zaffiro:~/Corsi/Reti/C> echocli 127.0.0.1

    pippopippopippopippo

    pippopippopippopippo

    ^D^D^D^D

    robdep@zaffiro:~/Corsi/Reti/C> psrobdep@zaffiro:~/Corsi/Reti/C> psrobdep@zaffiro:~/Corsi/Reti/C> psrobdep@zaffiro:~/Corsi/Reti/C> ps

    PID TTY PID TTY PID TTY PID TTY TIME CMDTIME CMDTIME CMDTIME CMD

    1077 pts/0 1077 pts/0 1077 pts/0 1077 pts/0 00:00:00 cat00:00:00 cat00:00:00 cat00:00:00 cat

    22084 pts/2 22084 pts/2 22084 pts/2 22084 pts/2 00:00:00 bash00:00:00 bash00:00:00 bash00:00:00 bash

    27162 pts/3 27162 pts/3 27162 pts/3 27162 pts/3 00:00:00 ssh00:00:00 ssh00:00:00 ssh00:00:00 ssh

    30007 pts/6 30007 pts/6 30007 pts/6 30007 pts/6 00:00:00 bash00:00:00 bash00:00:00 bash00:00:00 bash

    30331 pts/11 30331 pts/11 30331 pts/11 30331 pts/11 00:00:00 bash00:00:00 bash00:00:00 bash00:00:00 bash

    30761 pts/11 30761 pts/11 30761 pts/11 30761 pts/11 00:00:00 echosrv00:00:00 echosrv00:00:00 echosrv00:00:00 echosrv

    30765 pts/11 30765 pts/11 30765 pts/11 30765 pts/11 00:00:00 echosrv 00:00:00 echosrv 00:00:00 echosrv 00:00:00 echosrv

    30767 pts/11 30767 pts/11 30767 pts/11 30767 pts/11 00:00:00 echosrv 00:00:00 echosrv 00:00:00 echosrv 00:00:00 echosrv

    30768 pts/6 30768 pts/6 30768 pts/6 30768 pts/6 00:00:00 ps00:00:00 ps00:00:00 ps00:00:00 ps

    Il client viene uccisoIl client viene uccisoIl client viene uccisoIl client viene ucciso

    Il client viene uccisoIl client viene uccisoIl client viene uccisoIl client viene ucciso

    Ognli client che termina lascia uno zombie indica uno zombie

  • 23

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    45454545Signal handler

    Prompt > echoserver &Prompt > echoserver &Prompt > echoserver &Prompt > echoserver &

    [2] 19287[2] 19287[2] 19287[2] 19287

    prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1prompt > echoclient 127.0.0.1

    Ciao serverCiao serverCiao serverCiao server

    Ciao serverCiao serverCiao serverCiao server

    ^D^D^D^D

    Child 19293 terminatedChild 19293 terminatedChild 19293 terminatedChild 19293 terminated

    accept error: interrupted system callaccept error: interrupted system callaccept error: interrupted system callaccept error: interrupted system call

    void sig_child(int signo) {void sig_child(int signo) {void sig_child(int signo) {void sig_child(int signo) {

    pid_t pid;pid_t pid;pid_t pid;pid_t pid;

    int stat;int stat;int stat;int stat;

    while ( pid = waitpid(while ( pid = waitpid(while ( pid = waitpid(while ( pid = waitpid(----1,&stat,WNOHANG)) > 0) {1,&stat,WNOHANG)) > 0) {1,&stat,WNOHANG)) > 0) {1,&stat,WNOHANG)) > 0) {

    printf(Child %d terminatedprintf(Child %d terminatedprintf(Child %d terminatedprintf(Child %d terminated\\\\n,pid);n,pid);n,pid);n,pid);

    }}}}

    }}}}

    Utilizzando il gestore di segnali si evitano i processi zombie Appena il figlio finisce viene chiamata waitpid

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    46464646Interruzione delle system call

    Il segnale stato catturato dal padre durante lesecuzione di accept

    Il gestore del segnale viene eseguito

    Poich stata interrotta la funzione accept ritorna con il codice di errore EINTR

    Poich la gestione di tale errore non prevista il server termina lesecuzione

    Occorre tener presente questo problema In alcuni sistemi le system call sono

    automaticamente richiamate in altri no

  • 24

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    47474747Una possibile soluzione

    for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {

    clilen = sizeof(cliaddr);clilen = sizeof(cliaddr);clilen = sizeof(cliaddr);clilen = sizeof(cliaddr);

    if ( (connfd = accept(listenfd, &cliaddr, &clilen)) < 0) {if ( (connfd = accept(listenfd, &cliaddr, &clilen)) < 0) {if ( (connfd = accept(listenfd, &cliaddr, &clilen)) < 0) {if ( (connfd = accept(listenfd, &cliaddr, &clilen)) < 0) {

    if (errno = EINTR)if (errno = EINTR)if (errno = EINTR)if (errno = EINTR)

    continue;continue;continue;continue;

    else {else {else {else {

    perror(accept error);perror(accept error);perror(accept error);perror(accept error);

    exit(1);exit(1);exit(1);exit(1);

    }}}}

    }}}}

    }}}}

    Se la chiamata ad accept ritorna EINTR accept viene richiamata

    Se lerrore diverso da EINTR Si gestisce lerrore (nellesempio si chiama exit)

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    48484848Reset connessione e accept

    Un altro errore tipico da gestire con accept il reset della connessione prima della chiamata ad accept La connessione diventa ESTABLISHED Il client spedisce un RST Il server chiama accept

    Accept ritorna un codice di errore ECONNABORTED

    Il server pu richiamare accept per la prossima connessione

  • 25

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    49494949Terminazione del server

    Cosa succede se il server termina prematuramente?

    Al kill i socket descriptor vengono chiusi Un FIN viene spedito al client

    Il client spedisce Arrivederci al server permesso perch il client non ha chiuso il socket

    Il client chiama readline che ritorna EOF Non si aspetta di ricevere EOF quindi stampa il messaggio di

    errore e termina

    Prompt > echoclient 127.0.0.1Prompt > echoclient 127.0.0.1Prompt > echoclient 127.0.0.1Prompt > echoclient 127.0.0.1

    CiaoCiaoCiaoCiao

    CiaoCiaoCiaoCiao

    ArrivederciArrivederciArrivederciArrivederci

    Il server non risponde (dipende dal codice)Il server non risponde (dipende dal codice)Il server non risponde (dipende dal codice)Il server non risponde (dipende dal codice)

    Il server viene uccisoIl server viene uccisoIl server viene uccisoIl server viene ucciso

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    50505050SIGPIPE

    Cosa succede se il client ignora lerrore su readline e scrive nel socket? Questo pu capitare se il codice ha due write consecutive

    La prima fa s che il server spedisca RST La seconda crea il problema

    Viene generato un segnale di SIGPIPE Il processo termina se il segnale non viene catturato o ignorato

    Se SIGPIPE ignorato loperazione di write genera lerrore di EPIPE

    Soluzione semplice, quando non si deve reagire allerrore1. Ignorare (SIG_IGN) il segnale di SIGPIPE

    Assume che non occorre fare niente di speciale in tale circostanza2. Controllare lerrore di EPIPE sulle write e nel caso di errore

    terminare (non scrivere pi)

  • 26

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    51515151Macchina server non raggiungibile

    Unaltra possibile causa di errore se la macchina server non risponde proprio Diverso da uccidere il processo server (in quel caso

    vengono spediti FIN, RST) Pu dipendere dalla rete O dalla macchina server

    Il client bloccato in readline

    TCP ritrasmetter i dati per ricevere lACK fino ad un certo timeout

    La funzione di lettura dal socket ritorna un errore ETIMEOUT EHOSTUNREACH, ENETUNREACH

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    52525252Server shutdown and reboot

    La connessione viene stabilita

    Il server va gi e fa il reboot senza che il client se ne accorga Non c comunicazione durante lo shutdown (server

    scollegato dalla rete altrimenti spedisce FIN)

    Il client spedisce nuovi dati al server dopo il reboot Il server non ha pi il socket aperto TCP risponde ai dati con un RST

    Client in readline quando riceve RST Readline ritorna ECONNRESET

  • 27

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    53535353Server somma

    Solo la funziona che gestisce il clientvoid server_somma(int sockfd) {void server_somma(int sockfd) {void server_somma(int sockfd) {void server_somma(int sockfd) {

    int i, arg1, arg2;int i, arg1, arg2;int i, arg1, arg2;int i, arg1, arg2;

    ssize_t n;ssize_t n;ssize_t n;ssize_t n;

    char sendline[MAXLINE], rcvline[MAXLINE];char sendline[MAXLINE], rcvline[MAXLINE];char sendline[MAXLINE], rcvline[MAXLINE];char sendline[MAXLINE], rcvline[MAXLINE];

    char c;char c;char c;char c;

    for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {

    if ( (n = reti_readline(sockfd, rcvline, MAXLINE)) == 0)if ( (n = reti_readline(sockfd, rcvline, MAXLINE)) == 0)if ( (n = reti_readline(sockfd, rcvline, MAXLINE)) == 0)if ( (n = reti_readline(sockfd, rcvline, MAXLINE)) == 0)

    return; /* connection closed by other end */return; /* connection closed by other end */return; /* connection closed by other end */return; /* connection closed by other end */

    /* legge dalla stringa passata dal client i due interi /* legge dalla stringa passata dal client i due interi /* legge dalla stringa passata dal client i due interi /* legge dalla stringa passata dal client i due interi

    da sommare */da sommare */da sommare */da sommare */

    if( sscanf(rcvline, "%d %d", &arg1, &arg2) == 2 ) if( sscanf(rcvline, "%d %d", &arg1, &arg2) == 2 ) if( sscanf(rcvline, "%d %d", &arg1, &arg2) == 2 ) if( sscanf(rcvline, "%d %d", &arg1, &arg2) == 2 )

    /* converte il risultato in stringa e lo scrive nel /* converte il risultato in stringa e lo scrive nel /* converte il risultato in stringa e lo scrive nel /* converte il risultato in stringa e lo scrive nel

    buffer */buffer */buffer */buffer */

    sprintf(sendline, "%dsprintf(sendline, "%dsprintf(sendline, "%dsprintf(sendline, "%d\\\\n", arg1 + arg2);n", arg1 + arg2);n", arg1 + arg2);n", arg1 + arg2);

    else else else else

    sprintf(sendline, "input errorsprintf(sendline, "input errorsprintf(sendline, "input errorsprintf(sendline, "input error\\\\n");n");n");n");

    n = strlen(sendline);n = strlen(sendline);n = strlen(sendline);n = strlen(sendline);

    reti_writen(sockfd, sendline, n);reti_writen(sockfd, sendline, n);reti_writen(sockfd, sendline, n);reti_writen(sockfd, sendline, n);

    }}}}

    }}}}

    sommasrv.csommasrv.csommasrv.csommasrv.c

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    54545454Client somma

    Il codice del client somma un p pi complesso

    Deve gestire due input I dati in arrivo dal socket I dati digitati dallutente alla tastiera

    Questo problema verr affrontato in seguito IO multiplexing Select

    Il codice disponibile sulla pagina Web sommacli.c

  • 28

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    55555555Problema

    sunos5 > sommacli 206.62.226.33sunos5 > sommacli 206.62.226.33sunos5 > sommacli 206.62.226.33sunos5 > sommacli 206.62.226.33

    11 2211 2211 2211 22

    33333333

    ----11 11 11 11 ----44444444

    ----55555555

    bsdi > sommacli 206.62.226.33bsdi > sommacli 206.62.226.33bsdi > sommacli 206.62.226.33bsdi > sommacli 206.62.226.33

    11 2211 2211 2211 22

    33333333

    ----11 11 11 11 ----44444444

    ----16542537165425371654253716542537

    Client e server, stesso tipo di macchina

    Client e server, macchine di tipo diverso Una Sparc laltra Intel

    Sparc: big-endian, Intel: little-endian

    Prof. Roberto De Prisco

    Reti di Calcolatori

    Corso di laurea in Informatica

    A.A. 2007-2008

    Lezione

    Socket UDP

    3333

  • 29

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    57575757UDP

    TCP Trasporto orientato alla connessione, affidabile

    UDP Senza connessione, inaffidabile

    Ci sono situazione in cui sensato usare UDP

    Esempi DNS NFS SNMP

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    58585858Funzioni per i socket

    socket()socket()socket()socket()

    bind()bind()bind()bind()

    recvfrom()recvfrom()recvfrom()recvfrom()socket()socket()socket()socket()

    sendto()sendto()sendto()sendto()

    recvfrom()recvfrom()recvfrom()recvfrom()

    sendto()sendto()sendto()sendto()

    close()close()close()close()close()close()close()close()

    Aspetta un datagram

    Dati (richiesta)

    Dati (risposta)

    CLIENT

    CLIENT

    CLIENT

    CLIENT

    SERVER

    SERVER

    SERVER

    SERVER

    Tipica interazione per il protocollo UDP

    Aspetta un datagram

  • 30

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    59595959Spedire e ricevere datagrammi

    #include int recvfrom(int sd, void* buf, int nbytes, int flags, struct

    sockaddr* from, socklen_t *len);int sendto(int sd, const void* buf, int nbytes, int flags, const

    struct sockaddr* to, socklen_t len);

    Valore di ritorno: -1 se errore, byte letti o scritti se OK

    sd, buf e nbytes Il socket descriptor, i dati da scrivere o il buffer in cui leggere e la

    lunghezza dei dati/buffer flags = 0, per ora

    (vedremo a che serve con le funzioni di I/O avanzato) from o to, len

    Specificano la struttura che descrive il socket, il from e len verranno scritti dalla funzione Se sono nulli inizialmente significa che non siamo interessati a saperli e non

    verranno scritti Simili agli ultimi due parametri di accept

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    60606060Server echo con UDP

    int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int sockfd;int sockfd;int sockfd;int sockfd;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )

    err_sys("socket error");err_sys("socket error");err_sys("socket error");err_sys("socket error");bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);

    if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )err_sys("bind error");err_sys("bind error");err_sys("bind error");err_sys("bind error");

    server_echo_udp(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));}}}}

    void server_echo_udp(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen) {void server_echo_udp(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen) {void server_echo_udp(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen) {void server_echo_udp(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen) {int int int int n;n;n;n;socklen_t socklen_t socklen_t socklen_t len;len;len;len;char char char char mesg[MAXLINE];mesg[MAXLINE];mesg[MAXLINE];mesg[MAXLINE];for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {

    len = clilen;len = clilen;len = clilen;len = clilen;if( (n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cliaddr, &len)) < 0)if( (n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cliaddr, &len)) < 0)if( (n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cliaddr, &len)) < 0)if( (n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cliaddr, &len)) < 0)

    err_sys("recvfrom error");err_sys("recvfrom error");err_sys("recvfrom error");err_sys("recvfrom error");if( sendto(sockfd, mesg, n, 0, p_cliaddr, len) != n )if( sendto(sockfd, mesg, n, 0, p_cliaddr, len) != n )if( sendto(sockfd, mesg, n, 0, p_cliaddr, len) != n )if( sendto(sockfd, mesg, n, 0, p_cliaddr, len) != n )

    err_sys("sendto error");err_sys("sendto error");err_sys("sendto error");err_sys("sendto error");}}}}

    }}}}

    echoudpsrv.cechoudpsrv.cechoudpsrv.cechoudpsrv.c

  • 31

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    61616161Client echo con UDP (1)

    #include "basic.h"#include "basic.h"#include "basic.h"#include "basic.h"#include "echo.h"#include "echo.h"#include "echo.h"#include "echo.h"

    int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int sockfd;int sockfd;int sockfd;int sockfd;

    struct sockaddr_in servaddr;struct sockaddr_in servaddr;struct sockaddr_in servaddr;struct sockaddr_in servaddr;

    if (argc != 2)if (argc != 2)if (argc != 2)if (argc != 2)err_quit("usage: udpclient ");err_quit("usage: udpclient ");err_quit("usage: udpclient ");err_quit("usage: udpclient ");

    bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);inet_pton(AF_INET, argv[1], &servaddr.sin_addr);inet_pton(AF_INET, argv[1], &servaddr.sin_addr);inet_pton(AF_INET, argv[1], &servaddr.sin_addr);inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )err_sys("socket error");err_sys("socket error");err_sys("socket error");err_sys("socket error");

    client_echo_udp(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));client_echo_udp(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));client_echo_udp(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));client_echo_udp(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    exit(0);exit(0);exit(0);exit(0);}}}}

    echoudpcli.cechoudpcli.cechoudpcli.cechoudpcli.c

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    62626262Client echo con UDP (2)

    void client_echo_udp(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {int int int int n;n;n;n;char char char char sendline[MAXLINE], recvline[MAXLINE + 1];sendline[MAXLINE], recvline[MAXLINE + 1];sendline[MAXLINE], recvline[MAXLINE + 1];sendline[MAXLINE], recvline[MAXLINE + 1];char char char char buff[MAXLINE];buff[MAXLINE];buff[MAXLINE];buff[MAXLINE];socklen_t socklen_t socklen_t socklen_t len;len;len;len;struct sockaddr *p_replyaddr;struct sockaddr *p_replyaddr;struct sockaddr *p_replyaddr;struct sockaddr *p_replyaddr;

    p_replyaddr = malloc(servlen);p_replyaddr = malloc(servlen);p_replyaddr = malloc(servlen);p_replyaddr = malloc(servlen);

    while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {sendto(sockfd, sendline, strlen(sendline), 0, p_servaddr, servlen);sendto(sockfd, sendline, strlen(sendline), 0, p_servaddr, servlen);sendto(sockfd, sendline, strlen(sendline), 0, p_servaddr, servlen);sendto(sockfd, sendline, strlen(sendline), 0, p_servaddr, servlen);len = servlen;len = servlen;len = servlen;len = servlen;

    if( (n = recvfrom(sockfd, recvline, MAXLINE, 0, p_replyaddr, &len)) < 0 )if( (n = recvfrom(sockfd, recvline, MAXLINE, 0, p_replyaddr, &len)) < 0 )if( (n = recvfrom(sockfd, recvline, MAXLINE, 0, p_replyaddr, &len)) < 0 )if( (n = recvfrom(sockfd, recvline, MAXLINE, 0, p_replyaddr, &len)) < 0 )err_sys("recvfrom error");err_sys("recvfrom error");err_sys("recvfrom error");err_sys("recvfrom error");

    if( (len != servlen) || memcmp(p_servaddr, p_replyaddr, len) != 0 ) {if( (len != servlen) || memcmp(p_servaddr, p_replyaddr, len) != 0 ) {if( (len != servlen) || memcmp(p_servaddr, p_replyaddr, len) != 0 ) {if( (len != servlen) || memcmp(p_servaddr, p_replyaddr, len) != 0 ) {struct sockaddr_in *sin = (struct sockaddr_in *) p_replyaddr;struct sockaddr_in *sin = (struct sockaddr_in *) p_replyaddr;struct sockaddr_in *sin = (struct sockaddr_in *) p_replyaddr;struct sockaddr_in *sin = (struct sockaddr_in *) p_replyaddr;err_msg("risposta da %s ignorataerr_msg("risposta da %s ignorataerr_msg("risposta da %s ignorataerr_msg("risposta da %s ignorata\\\\n", n", n", n",

    inet_ntop(AF_INET, &sininet_ntop(AF_INET, &sininet_ntop(AF_INET, &sininet_ntop(AF_INET, &sin---->sin_addr, buff, sizeof(buff)));>sin_addr, buff, sizeof(buff)));>sin_addr, buff, sizeof(buff)));>sin_addr, buff, sizeof(buff)));continue;continue;continue;continue;

    }}}}

    recvline[n] = 0;recvline[n] = 0;recvline[n] = 0;recvline[n] = 0;fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);

    }}}}}}}}

  • 32

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    63636363Controllo sul mittente

    Il client controlla che il datagram di risposta venga dal server

    Infatti potrebbe ricevere un qualsiasi altro datagram Tale datagram sarebbe interpratato come la risposta

    del server

    Esercizio Provare a creare una situazione del genere Sul sito c il codice di spedisce_dg.c

    Permette di spedire un datagram verso una porta UDP

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    64646464Datagrammi perduti

    Cosa succede se un datagram si perde? Per esempio un router lo butta via

    Chi lo sta aspettando (server o client) rimane bloccato in attesa

    Per evitare questo problema si pu usare un timeout In alcuni casi non basta Non sappiamo se il messaggio del client non mai

    arrivato al server oppure se la risposta del server non arrivata al client

    In alcuni casi (es. transazioni bancarie) fa molta differenza

  • 33

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    65656565Connect e UDP

    Sebbene UPD sia senza connessione possibile chiamare la funzione connect su un socket UDP

    Non si crea una connessione (handshake TCP)

    Semplicemente il kernel memorizza lindirizzo IP e la porta con cui si vuole comunicare

    Quindi dobbiamo distinguire tra Socket UDP connesso Socket UDP non connesso

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    66666666Socket UDP connesso

    Non si pu specificare il destinatario: quello specificato in connect Non si usa sendto ma write o send I pacchetti verrano automaticamente spediti allindirizzo

    specificato nella chiamata a connect

    I datagram letti sono quelli che arrivano dallindirizzo connesso Non si usa recvfrom, ma si usa read o readv Ci limita un server UDP a comunicare con un solo

    client

    Errori asincroni possono essere controllati Un socket UDP non connesso non pu controllare errori

    asincroni

  • 34

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    67676767connect

    possibili chiamare connect pi di una volta

    Pu essere usato per cambiare lindirizzo con cui si vuol comunicare Disconnettere il socket (specificando

    AF_UNSPEC come famiglia di protocolli nel campo sin_family) Potrebbe ritornare lerrore EAFNOSUPPORT, ma

    non un problema

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    68686868UDP client versione connect

    void client_echo_udp_conn(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp_conn(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp_conn(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {void client_echo_udp_conn(FILE *fp, int sockfd, const struct sockaddr *p_servaddr, socklen_t servlen) {

    int n;int n;int n;int n;char sendline[MAXLINE], recvline[MAXLINE + 1];char sendline[MAXLINE], recvline[MAXLINE + 1];char sendline[MAXLINE], recvline[MAXLINE + 1];char sendline[MAXLINE], recvline[MAXLINE + 1];

    if( connect(sockfd, (struct sockaddr *) p_servaddr, servlen) < 0 )if( connect(sockfd, (struct sockaddr *) p_servaddr, servlen) < 0 )if( connect(sockfd, (struct sockaddr *) p_servaddr, servlen) < 0 )if( connect(sockfd, (struct sockaddr *) p_servaddr, servlen) < 0 )err_sys("connect error");err_sys("connect error");err_sys("connect error");err_sys("connect error");

    while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {while (fgets(sendline, MAXLINE, fp) != NULL) {

    write(sockfd, sendline, strlen(sendline));write(sockfd, sendline, strlen(sendline));write(sockfd, sendline, strlen(sendline));write(sockfd, sendline, strlen(sendline));

    n = read(sockfd, recvline, MAXLINE);n = read(sockfd, recvline, MAXLINE);n = read(sockfd, recvline, MAXLINE);n = read(sockfd, recvline, MAXLINE);

    recvline[n] = 0; /* null terminate */recvline[n] = 0; /* null terminate */recvline[n] = 0; /* null terminate */recvline[n] = 0; /* null terminate */fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);

    }}}}}}}}

    echoudpcliechoudpcliechoudpcliechoudpcli----connect.cconnect.cconnect.cconnect.c

  • 35

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    69696969Inaffidabilit di UDP

    UDP non d alcuna garanzia sulla consegna dei datagram

    Consideriamo la seguente applicazione client server UDP Il server riceve datagram e semplicemente li

    conta Pu essere interrotto con CTRL-C, ce un gestore di

    segnale che semplicemente stampa quanti datagram sono stati ricevuti

    Il client spedisce un serie di pacchetti, senza aspettare alcuna risposta

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    70707070UDP echo server count (1)

    #include "basic.h"#include "basic.h"#include "basic.h"#include "basic.h"#include "echo.h"#include "echo.h"#include "echo.h"#include "echo.h"

    void server_echo_udp_count(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen);void server_echo_udp_count(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen);void server_echo_udp_count(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen);void server_echo_udp_count(int sockfd, struct sockaddr *p_cliaddr, socklen_t clilen);static void gestisci_interrupt(int signo); static void gestisci_interrupt(int signo); static void gestisci_interrupt(int signo); static void gestisci_interrupt(int signo);

    int count = 0;int count = 0;int count = 0;int count = 0;

    int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int main(int argc, char **argv) {int sockfd;int sockfd;int sockfd;int sockfd;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;struct sockaddr_in servaddr, cliaddr;

    if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )err_sys("socket error");err_sys("socket error");err_sys("socket error");err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);servaddr.sin_port = htons(PORT);

    if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )if( bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )err_sys("bind error");err_sys("bind error");err_sys("bind error");err_sys("bind error");

    signal(SIGINT, gestisci_interrupt);signal(SIGINT, gestisci_interrupt);signal(SIGINT, gestisci_interrupt);signal(SIGINT, gestisci_interrupt);

    server_echo_udp_count(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp_count(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp_count(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));server_echo_udp_count(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));}}}}

    echoudpcliechoudpcliechoudpcliechoudpcli----count.ccount.ccount.ccount.c

  • 36

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    71717171UDP echo server count (2)

    void server_echo_udp_count(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) {void server_echo_udp_count(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) {void server_echo_udp_count(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) {void server_echo_udp_count(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) {int int int int n;n;n;n;socklen_t socklen_t socklen_t socklen_t len;len;len;len;char char char char mesg[MAXLINE];mesg[MAXLINE];mesg[MAXLINE];mesg[MAXLINE];

    n = 240 * 1024;n = 240 * 1024;n = 240 * 1024;n = 240 * 1024;setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));

    for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {for ( ; ; ) {len = clilen;len = clilen;len = clilen;len = clilen;recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);count++;count++;count++;count++;sleep(1); /* rallentiamo il server */sleep(1); /* rallentiamo il server */sleep(1); /* rallentiamo il server */sleep(1); /* rallentiamo il server */

    }}}}}}}}

    static void gestisci_interrupt(int signo) {static void gestisci_interrupt(int signo) {static void gestisci_interrupt(int signo) {static void gestisci_interrupt(int signo) {printf("printf("printf("printf("\\\\nDatagrams ricevuti: %dnDatagrams ricevuti: %dnDatagrams ricevuti: %dnDatagrams ricevuti: %d\\\\n", count);n", count);n", count);n", count);exit(0);exit(0);exit(0);exit(0);

    }}}}

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    72727272UDP echo client count

    Il client come gli altri Cambia solo la funzione che spedisce i datagram

    Cosa succede se usiamo questo client-server?

    #define NDG 2000 /* #datagrams to send */#define NDG 2000 /* #datagrams to send */#define NDG 2000 /* #datagrams to send */#define NDG 2000 /* #datagrams to send */#define DGLEN 1400 /* length of each datagram */#define DGLEN 1400 /* length of each datagram */#define DGLEN 1400 /* length of each datagram */#define DGLEN 1400 /* length of each datagram */

    void client_echo_udp_count(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen) {void client_echo_udp_count(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen) {void client_echo_udp_count(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen) {void client_echo_udp_count(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen) {int i;int i;int i;int i;char sendline[MAXLINE];char sendline[MAXLINE];char sendline[MAXLINE];char sendline[MAXLINE];

    for (i = 0; i < NDG; i++) {for (i = 0; i < NDG; i++) {for (i = 0; i < NDG; i++) {for (i = 0; i < NDG; i++) {sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);

    }}}}}}}}

    echoudpcliechoudpcliechoudpcliechoudpcli----count.ccount.ccount.ccount.c

  • 37

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    73737373Errori non segnalatirobdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat ----s | grep s | grep s | grep s | grep ----C4 "Udp" | tail C4 "Udp" | tail C4 "Udp" | tail C4 "Udp" | tail ----5; 5; 5; 5;

    Udp:Udp:Udp:Udp:

    6686 packets received6686 packets received6686 packets received6686 packets received

    2012 packets to unknown port received.2012 packets to unknown port received.2012 packets to unknown port received.2012 packets to unknown port received.

    9674 packet receive errors9674 packet receive errors9674 packet receive errors9674 packet receive errors

    18634 packets sent18634 packets sent18634 packets sent18634 packets sent

    robdep@zircone:~/Corsi/Reti/C> echoudpsrvrobdep@zircone:~/Corsi/Reti/C> echoudpsrvrobdep@zircone:~/Corsi/Reti/C> echoudpsrvrobdep@zircone:~/Corsi/Reti/C> echoudpsrv----countcountcountcount

    Datagrams ricevuti: 11 Datagrams ricevuti: 11 Datagrams ricevuti: 11 Datagrams ricevuti: 11

    robdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat robdep@zircone:~/Corsi/Reti/C> netstat ----s | grep s | grep s | grep s | grep ----C4 "Udp" | tail C4 "Udp" | tail C4 "Udp" | tail C4 "Udp" | tail ----5; 5; 5; 5;

    Udp:Udp:Udp:Udp:

    7206 packets received7206 packets received7206 packets received7206 packets received

    2012 packets to unknown port received.2012 packets to unknown port received.2012 packets to unknown port received.2012 packets to unknown port received.

    11154 packet receive errors11154 packet receive errors11154 packet receive errors11154 packet receive errors

    20634 packets sent20634 packets sent20634 packets sent20634 packets sent

    Client in unaltra shell; dopo un pCTRLClient in unaltra shell; dopo un pCTRLClient in unaltra shell; dopo un pCTRLClient in unaltra shell; dopo un pCTRL----CCCC

    robdep@zircone:~/Corsi/Reti/C> echoudpclirobdep@zircone:~/Corsi/Reti/C> echoudpclirobdep@zircone:~/Corsi/Reti/C> echoudpclirobdep@zircone:~/Corsi/Reti/C> echoudpcli----count 127.0.0.1count 127.0.0.1count 127.0.0.1count 127.0.0.1

    robdep@zircone:~/Corsi/Reti/C> robdep@zircone:~/Corsi/Reti/C> robdep@zircone:~/Corsi/Reti/C> robdep@zircone:~/Corsi/Reti/C>

    Prof. Roberto De Prisco

    Reti di Calcolatori

    Corso di laurea in Informatica

    A.A. 2007-2008

    Lezione

    I/O Multiplexing

    4444

  • 38

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    75757575Problema

    Un programma deve gestire due input simultaneamente Standard input (leggere da tastiera) Un socket (leggere dal socket)

    Abbiamo visto un esempio in cui il client era bloccato a leggere da standard input Non poteva leggere il FIN sul socket

    Normalmente una funzione di I/O si blocca se non ci sono dati da leggere

    Serve un modo per poter aspettare da pi canali di input Il primo che produce dati viene letto

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    76767676Modelli di I/O

    Vari modelli di Input/Output1. Blocking 2. Nonblocking3. I/O multiplexing4. Guidato dai segnali5. Asincrono

    Sincrono: il processo si blocca (quando chiama loperazione di lettura) fino alla conclusione delloperazione

    In una operazione di lettura da un canale di I/O possiamo distinguere due fasi1. Attesa per i dati da parte del kernel2. Copia dei dati dal kernel al processo che deve usarli

    sincronisincronisincronisincroni

  • 39

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    77777777Blocking I/O

    applicazioneapplicazioneapplicazioneapplicazione kernelkernelkernelkernel

    Recvfrom System callSystem callSystem callSystem call Non ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram pronti

    datagram prontodatagram prontodatagram prontodatagram pronto

    Copia datagramCopia datagramCopia datagramCopia datagram

    Copia completataCopia completataCopia completataCopia completataProcesso continua (elabora il Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il datagram)datagram)datagram)datagram)

    BLOCCATA

    BLOCCATA

    BLOCCATA

    BLOCCATA

    Ritorna OKRitorna OKRitorna OKRitorna OK

    FASE 1: FASE 1: FASE 1: FASE 1:

    attesaattesaattesaattesa

    FASE 2: FASE 2: FASE 2: FASE 2:

    copiacopiacopiacopia

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    78787878Nonblocking I/O

    applicazioneapplicazioneapplicazioneapplicazione kernelkernelkernelkernel

    Recvfrom System callSystem callSystem callSystem callNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram pronti

    datagram prontodatagram prontodatagram prontodatagram pronto

    Copia datagramCopia datagramCopia datagramCopia datagram

    Copia completataCopia completataCopia completataCopia completataProcesso continua (elabora il Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il datagram)datagram)datagram)datagram)

    BLOCCATA

    BLOCCATA

    BLOCCATA

    BLOCCATA

    Ritorna OKRitorna OKRitorna OKRitorna OK

    FASE 1: FASE 1: FASE 1: FASE 1:

    attesaattesaattesaattesa

    FASE 2: FASE 2: FASE 2: FASE 2:

    copiacopiacopiacopia

    EWOULDBLOCK

    EWOULDBLOCK

    System callSystem callSystem callSystem call

    System callSystem callSystem callSystem call

    Recvfrom

    Recvfrom

  • 40

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    79797979I/O multiplexing

    applicazioneapplicazioneapplicazioneapplicazione kernelkernelkernelkernel

    selectSystem callSystem callSystem callSystem call Non ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram pronti

    datagram prontodatagram prontodatagram prontodatagram pronto

    Copia datagramCopia datagramCopia datagramCopia datagram

    Copia completataCopia completataCopia completataCopia completataProcesso continua (elabora il Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il datagram)datagram)datagram)datagram)

    BLOCCATA

    BLOCCATA

    BLOCCATA

    BLOCCATA

    Ritorna OKRitorna OKRitorna OKRitorna OK

    FASE 1: FASE 1: FASE 1: FASE 1:

    attesaattesaattesaattesa

    FASE 2: FASE 2: FASE 2: FASE 2:

    copiacopiacopiacopia

    System callSystem callSystem callSystem callRecvfrom

    BLOCCATA

    BLOCCATA

    BLOCCATA

    BLOCCATA

    Ritorna prontoRitorna prontoRitorna prontoRitorna pronto

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    80808080I/O guidato dai segnali

    applicazioneapplicazioneapplicazioneapplicazione kernelkernelkernelkernel

    signalSystem callSystem callSystem callSystem call

    datagram prontodatagram prontodatagram prontodatagram pronto

    Copia datagramCopia datagramCopia datagramCopia datagram

    Copia completataCopia completataCopia completataCopia completataProcesso continua (elabora il Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il datagram)datagram)datagram)datagram)

    BLOCCATA

    BLOCCATA

    BLOCCATA

    BLOCCATA

    Ritorna OKRitorna OKRitorna OKRitorna OK

    FASE 1: FASE 1: FASE 1: FASE 1:

    attesaattesaattesaattesa

    FASE 2: FASE 2: FASE 2: FASE 2:

    copiacopiacopiacopia

    System callSystem callSystem callSystem callRecvfrom

    SEGNALESEGNALESEGNALESEGNALEGESTORE SEGNALE

    Non ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram pronti

  • 41

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    81818181I/O asincrono

    applicazioneapplicazioneapplicazioneapplicazione kernelkernelkernelkernel

    aio_readSystem callSystem callSystem callSystem call

    datagram prontodatagram prontodatagram prontodatagram pronto

    Copia datagramCopia datagramCopia datagramCopia datagram

    Copia completataCopia completataCopia completataCopia completata

    FASE 1: FASE 1: FASE 1: FASE 1:

    attesaattesaattesaattesa

    FASE 2: FASE 2: FASE 2: FASE 2:

    copiacopiacopiacopia

    SEGNALESEGNALESEGNALESEGNALEGESTORE SEGNALE

    Non ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram prontiNon ci sono datagram pronti

    Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il Processo continua (elabora il datagram)datagram)datagram)datagram)

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    82828282Funzione select

    #include #include int select(int maxfd, fd_set readset, fd_set writeset,

    fd_set exceptionset, const struct timeval *timeout);

    Valore di ritorno: -1 se errore, 0 se timeout, numero di descrittori pronti

    Permette di aspettare che uno o pi file descriptor siano pronti per essere letti

    Il timeout dato dalla strutturastruct timeval {

    long tv_sec;long tv_usec;

    }

  • 42

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    83838383Parametri select

    Timeout1. Puntatore nullo: aspetta senza timeout (fino a che un descrittore

    pronto)2. Struttura con un timeout non zero: aspetta fino al timeout, poi

    ritorna anche se non ci sono descrittori pronti Anche se possiamo specificare i microsecondi alcuni kernel

    arrotondano a multipli di 10 microsecondi Alcuni sistemi Linux modificano la struttura timeout (vale il tempo

    rimanente al momento del ritorno)3. Struttura con un timeout pari a 0: non aspettare, ritorna

    immediatamente (polling)

    File descriptor da controllare Readset: pronti per la lettura Writeset: pronti per la scrittura Exceptionset: condizioni particolari

    Arrivo di dati fuori banda su un socket Informazioni di controllo da uno pseudo terminale

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    84848484Parametri select

    Per descriveri gli insiemi si usa la struttura fd_set che un insieme di bit void FD_ZERO(fd_set *fdset);

    Azzera la struttura fdset void FD_SET(int fd, fd_set *fdset);

    Mette a 1 il bit relativo al file descriptor fd void FD_CLR(int fd, fd_set *fdset);

    Mette a 0 il bit relativo al file descriptor fd int FD_ISSET(int fd, fd_set *fdset);

    Controlla se il bit relativo al file descriptor fd a 1

    La costante FD_SETSIZE (select.h) il numero di descrittori in fd_set (solitamente 1024)

    maxfd: il numero massimo di descrittori effetivamente usati Usato per efficienza dal kernel Es. se siamo interessati ai descrittori 1,4,7,9 maxfd deve valere

    10 (i file descriptor iniziano da 0)

  • 43

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    85858585Descrittori pronti

    Quando un socket descriptor pronto per essere usato?

    Socket in lettura Quando c almeno un byte da leggere

    La soglia si pu cambiare con le opzioni dei socket Il socket stato chiuso in lettura

    Es. stato ricevuto il FIN Loperazione di lettura ritorna EOF

    Il socket un listening socket e ci sono delle connessioni completate

    C un errore Loperazione di lettura ritorner -1 e errno specificher lerrore

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    86868686Descrittori pronti

    Socket in scrittura Il numero di byte di spazio disponibile nel buffer del

    kernel maggiore di 2048 La soglia si pu cambiare con le opzioni dei socket Loperazione di scrittura ritorna il numero di byte effettivamente

    passati al livello di trasporto Il socket stato chiuso in scrittura

    Unoperazione di scrittura genera SIGPIPE C un errore

    Loperazione di scrittura ritorner -1 e errno specificher lerrore

    Eccezioni per socket Arrivo di dati fuori banda

  • 44

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    87878787echoclient versione select (1)

    void client_echo_select(FILE *fp, int sockfd) {void client_echo_select(FILE *fp, int sockfd) {void client_echo_select(FILE *fp, int sockfd) {void client_echo_select(FILE *fp, int sockfd) {

    int maxfdl;int maxfdl;int maxfdl;int maxfdl;

    fd_set rset;fd_set rset;fd_set rset;fd_set rset;

    char sendline[MAXLINE], recvline[MAXLINE];char sendline[MAXLINE], recvline[MAXLINE];char sendline[MAXLINE], recvline[MAXLINE];char sendline[MAXLINE], recvline[MAXLINE];

    int n;int n;int n;int n;

    FD_ZERO(&rset);FD_ZERO(&rset);FD_ZERO(&rset);FD_ZERO(&rset);

    for( ; ; ) {for( ; ; ) {for( ; ; ) {for( ; ; ) {

    FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);

    FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);

    maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;

    if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )

    err_sys("select error");err_sys("select error");err_sys("select error");err_sys("select error");

    if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {

    if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {

    if( errno == EPIPE ) {if( errno == EPIPE ) {if( errno == EPIPE ) {if( errno == EPIPE ) {

    err_msg(%s [%d]: server disconnesso, __FILE__,__LINE__);err_msg(%s [%d]: server disconnesso, __FILE__,__LINE__);err_msg(%s [%d]: server disconnesso, __FILE__,__LINE__);err_msg(%s [%d]: server disconnesso, __FILE__,__LINE__);

    break;break;break;break;

    }}}}

    elseelseelseelse

    err_sys("readline error");err_sys("readline error");err_sys("readline error");err_sys("readline error");

    } } } }

    echocliechocliechocliechocli----slct.cslct.cslct.cslct.c

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    88888888echoclient versione select (2)

    if (n == 0)if (n == 0)if (n == 0)if (n == 0)

    err_quit(%s [%d]: server disconnesso,__FILE__,__LINE__);err_quit(%s [%d]: server disconnesso,__FILE__,__LINE__);err_quit(%s [%d]: server disconnesso,__FILE__,__LINE__);err_quit(%s [%d]: server disconnesso,__FILE__,__LINE__);

    fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);

    }}}}

    if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {

    if( fgets(sendline, MAXLINE, fp) == NULL) if( fgets(sendline, MAXLINE, fp) == NULL) if( fgets(sendline, MAXLINE, fp) == NULL) if( fgets(sendline, MAXLINE, fp) == NULL)

    return;return;return;return;

    if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)

    err_sys("write error");err_sys("write error");err_sys("write error");err_sys("write error");

    }}}}

    }}}}

    }}}}

    Il client riesce a gestire sia linput da tastiera che linput dal socket

    Se il server termina viene spedito un EOF sul socket Il client lo riceve e termina la connessione Senza select il client se ne sarebbe accorto dopo

  • 45

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    89898989echoclient e select

    Condizioni gestite da select in lettura su stdin ed un socket

    Data o EOFData o EOFData o EOFData o EOFstdinstdinstdinstdin

    RSTRSTRSTRST FINFINFINFINdatadatadatadata

    socketsocketsocketsocket

    ClientClientClientClient

    TCPTCPTCPTCP

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    90909090Stop-and-wait

    Il client opera in modalit stop-and-wait: Spedisce una linea di input e si blocca in attesa

    della risposta del server echoCCCC

    SSSS

    Tempo 0

    datidatidatidati

    Tempo 1

    datidatidatidati

    Tempo 2

    datidatidatidati

    Tempo 3

    datidatidatidati

    SSSS

    Tempo 4

    echoechoechoecho

    Tempo 5

    echoechoechoecho

    Tempo 6

    echoechoechoecho

    CCCC

    Tempo 7

    echoechoechoecho

  • 46

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    91919191Batch input

    Si spediscono le richieste consecutivamente senza aspettare le risposte, che arriveranno dopo

    CCCC

    Tempo 0

    d1d1d1d1

    Tempo 1

    d1d1d1d1CCCC d2d2d2d2

    Tempo 2

    d1d1d1d1CCCC d3d3d3d3 d2d2d2d2

    SSSS

    Tempo 3

    d1d1d1d1CCCC d4d4d4d4 d3d3d3d3 d2d2d2d2

    SSSS

    Tempo 4

    r1r1r1r1

    d5d5d5d5 d4d4d4d4 d3d3d3d3 d2d2d2d2CCCC SSSS

    Tempo 5

    r1r1r1r1 r2r2r2r2

    d5d5d5d5 d4d4d4d4 d3d3d3d3d6d6d6d6CCCC

    SSSS

    SSSS

    Tempo 6

    r1r1r1r1 r3r3r3r3r2r2r2r2

    d5d5d5d5 d4d4d4d4d6d6d6d6d7d7d7d7CCCC

    SSSS

    SSSS

    CCCC

    Tempo 7

    r1r1r1r1 r4r4r4r4r3r3r3r3r2r2r2r2

    d6d6d6d6 d5d5d5d5d7d7d7d7d8d8d8d8

    SSSS

    SSSSCCCC

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    92929292Shutdown della connessione

    Quando il client finisce di spedire non pu chiudere il socket Ci possono esser ancora dati in arrivo

    Si deve chiudere il socket solo in scrittura e lasciarlo aperto in lettura Spedire il FIN solo in una direzione

    #include int shutdown(int sockfd, int howto);

    Valore di ritorno: -1 se errore, 0 se OK

    howto = SHUT_RD, SHUT_WR, SHUT_RDWR

  • 47

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    93939393echoclient versione shutdown

    void client_echo_shutdown(FILE *fp, int sockfd) {void client_echo_shutdown(FILE *fp, int sockfd) {void client_echo_shutdown(FILE *fp, int sockfd) {void client_echo_shutdown(FILE *fp, int sockfd) {

    int int int int maxfdl, stdineof;maxfdl, stdineof;maxfdl, stdineof;maxfdl, stdineof;

    fd_set fd_set fd_set fd_set rset;rset;rset;rset;

    char char char char sendline[MAXLINE], recvline[MAXLINE];sendline[MAXLINE], recvline[MAXLINE];sendline[MAXLINE], recvline[MAXLINE];sendline[MAXLINE], recvline[MAXLINE];

    int int int int n;n;n;n;

    FD_ZERO(&rset);FD_ZERO(&rset);FD_ZERO(&rset);FD_ZERO(&rset);

    for( ; ; ) {for( ; ; ) {for( ; ; ) {for( ; ; ) {

    FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);FD_SET(fileno(fp), &rset);

    FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);FD_SET(sockfd, &rset);

    maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;maxfdl = MAX(fileno(fp), sockfd) + 1;

    if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )if( select(maxfdl, &rset, NULL, NULL, NULL) < 0 )

    err_sys("select error");err_sys("select error");err_sys("select error");err_sys("select error");

    if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {if( FD_ISSET(sockfd, &rset) ) {

    if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {if ( (n = reti_readline(sockfd, recvline, MAXLINE)) < 0) {

    if( errno == EPIPE ) {if( errno == EPIPE ) {if( errno == EPIPE ) {if( errno == EPIPE ) {

    err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);

    break;break;break;break;

    }}}}

    elseelseelseelse

    err_sys("readline error");err_sys("readline error");err_sys("readline error");err_sys("readline error");

    } } } }

    echocliechocliechocliechocli----shtd.cshtd.cshtd.cshtd.c

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    94949494echoclient versione shutdown

    if (n == 0) {if (n == 0) {if (n == 0) {if (n == 0) {

    if( stdineof == 1 )if( stdineof == 1 )if( stdineof == 1 )if( stdineof == 1 )

    return;return;return;return;

    else {else {else {else {

    err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);err_msg("%s [%d]: server disconnesso",__FILE__,__LINE__);

    exit(exit(exit(exit(----1);1);1);1);

    }}}}

    }}}}

    fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);fputs(recvline, stdout);

    }}}}

    if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {if( FD_ISSET(fileno(fp), &rset) ) {

    if( fgets(sendline, MAXLINE, fp) == NULL) {if( fgets(sendline, MAXLINE, fp) == NULL) {if( fgets(sendline, MAXLINE, fp) == NULL) {if( fgets(sendline, MAXLINE, fp) == NULL) {

    stdineof = 1;stdineof = 1;stdineof = 1;stdineof = 1;

    shutdown(sockfd, SHUT_WR);shutdown(sockfd, SHUT_WR);shutdown(sockfd, SHUT_WR);shutdown(sockfd, SHUT_WR);

    FD_CLR(fileno(fp), &rset);FD_CLR(fileno(fp), &rset);FD_CLR(fileno(fp), &rset);FD_CLR(fileno(fp), &rset);

    continue;continue;continue;continue;

    }}}}

    if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)if( (reti_writen(sockfd, sendline, strlen(sendline))) < 0)

    err_sys("write error");err_sys("write error");err_sys("write error");err_sys("write error");

    }}}}

    }}}}

    }}}}

  • 48

    LABORATORIOLABORATORIOLABORATORIOLABORATORIO

    Autunno 2007Autunno 2007Autunno 2007Autunno 2007

    95959595Select per il server Possiamo usare select anche nel server

    Al posto di creare un figlio per ogni connessione Select pu leggere da tutti i client connessi

    Strutture dati utilizzate Array rset, contiene file descriptor dei socket utilizzati

    dal server (sia listening che connessi) Array client, contiene interi