Cominciato a scrivere qualcosa ...
authorSimone Piccardi <piccardi@gnulinux.it>
Sun, 29 Feb 2004 18:00:22 +0000 (18:00 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sun, 29 Feb 2004 18:00:22 +0000 (18:00 +0000)
img/udp_connection.dia
othersock.tex

index c681fab..d44c6c3 100644 (file)
Binary files a/img/udp_connection.dia and b/img/udp_connection.dia differ
index d7bc4c0..868ca66 100644 (file)
@@ -29,30 +29,34 @@ principali e le modalit
 \label{sec:UDP_characteristics}
 
 Come illustrato in \secref{sec:net_udp} UDP è un protocollo molto semplice che
-non supporta le connessioni e non è affidabile: i dati vengono inviati in
-forma di pacchetti, e non ne è assicurata né la effettiva ricezione né
-l'odinamento.
+non supporta le connessioni e non è affidabile: esso si appoggia direttamente
+sopra IP (per i dettagli sul protocollo si veda \secref{sec:udp_protocol}).  I
+dati vengono inviati in forma di pacchetti, e non ne è assicurata né la
+effettiva ricezione né l'arrivo nell'ordine in cui vengono inviati. Il
+vantaggio del protocollo è la velocità, non è necessario trasmettere le
+informazioni di controllo ed il risultato è una trasmissione di dati più
+veloce ed immediata.
 
 Questo significa che a differenza dei socket TCP i socket UDP non supportano
 una comunicazione di tipo \textit{stream} in cui si ha a disposizione un
-flusso continuo di dati che può essere letto un po' alla volta, ma di tipo
-\textit{datagram}, in cui i dati arrivano in singoli blocchi che devono essere
-letti integralmente.
-
-Questo diverso comportamento significa anche che i socket UDP, pur restando
-nella famiglia \const{PF\_INET}\footnote{o \const{PF\_INET6} qualora si usasse
-  invece il protocollo IPv6.} devono essere aperti quando si usa la funzione
-\func{socket} (si riveda quanto illustrato a suo tempo in
-\tabref{tab:sock_sock_valid_combinations}) utilizzando come valore per il tipo
-di socket \const{SOCK\_DGRAM}.
-
-Questa differenza comporta ovviamente il fatto che anche le modalità con cui
-si usano i socket UDP sono completamente diverse rispetto ai socket TCP, ed in
+flusso continuo di dati che può essere letto un po' alla volta, ma piuttosto
+una comunicazione di tipo \textit{datagram}, in cui i dati arrivano in singoli
+blocchi che devono essere letti integralmente.
+
+Questo diverso comportamento significa anche che i socket UDP, pur
+appartenendo alla famiglia \const{PF\_INET}\footnote{o \const{PF\_INET6}
+  qualora si usasse invece il protocollo IPv6, che pure supporta UDP.} devono
+essere aperti quando si usa la funzione \func{socket} (si riveda quanto
+illustrato a suo tempo in \tabref{tab:sock_sock_valid_combinations})
+utilizzando per il tipo di socket il valore \const{SOCK\_DGRAM}.
+
+Questa differenza comporta ovviamente che anche le modalità con cui si usano i
+socket UDP sono completamente diverse rispetto ai socket TCP, ed in
 particolare non esistendo il concetto di connessione non esiste il meccanismo
-del \textit{three way handshake} nè quello di stati del protocollo, in realtà
-tutto quello che avviene nella comunicazione attraverso dei socket UDP è la
-trasmissione di un pacchetto da un client ad un server o viceversa, secondo lo
-schema illustrato in \figref{fig:UDP_packet-exchange}.
+del \textit{three way handshake} nè quello degli stati del protocollo. In
+realtà tutto quello che avviene nella comunicazione attraverso dei socket UDP
+è la trasmissione di un pacchetto da un client ad un server o viceversa,
+secondo lo schema illustrato in \figref{fig:UDP_packet-exchange}.
 
 \begin{figure}[htb]
   \centering
@@ -62,20 +66,200 @@ schema illustrato in \figref{fig:UDP_packet-exchange}.
   \label{fig:UDP_packet-exchange}
 \end{figure}
 
-Anche se UDP è completamente diverso rispetto a TCP resta identica 
+Come illustrato in \figref{fig:UDP_packet-exchange} la struttura generica di
+un server UDP prevede, una volta creato il socket, la chiamata a \func{bind}
+per mettersi in ascolto dei dati. Questa è l'unica parte comune con un server
+TCP: non essendovi il concetto di connessione le funzioni \func{listen} ed
+\func{accept} non sono mai utilizzate nel caso di server UDP. La ricezione dei
+dati dal client avviene attraverso la funzione \func{recvfrom}, mentre una
+eventuale risposta sarà inviata con la funzione \func{sendto}. 
+
+Da parte del client invece, una volta creato il socket non sarà necessario
+connettersi con \func{connect} (anche se, come vedremo in
+\secref{sec:UDP_connect}, è possibile usare questa funzione, con un
+significato comunque diverso) ma si potrà effettuare direttamente una
+richiesta inviando un pacchetto con la funzione \func{sendto} e si potrà
+leggere una eventuale risposta con la funzione \func{recvfrom}.
 
+Anche se UDP è completamente diverso rispetto a TCP resta identica la
+possibilità di gestire più canali di comunicazione fra due macchine
+utilizzando le porte. In questo caso il server dovrà usare comunque la
+funzione \func{bind} per scegliere la porta su cui ricevere i dati, e come nel
+caso dei socket TCP si potrà usare il comando \cmd{netstat}\footnote{per
+  ottenere il risultato mostrato occorre usare le opzioni \texttt{-anu}.} per
+verificare quali socket sono in ascolto:
+\begin{verbatim}
+Active Internet connections (servers and established)
+Proto Recv-Q Send-Q Local Address           Foreign Address         State
+udp        0      0 0.0.0.0:32768           0.0.0.0:*
+udp        0      0 192.168.1.2:53          0.0.0.0:*
+udp        0      0 127.0.0.1:53            0.0.0.0:*
+udp        0      0 0.0.0.0:67              0.0.0.0:*
+\end{verbatim}
+in questo caso abbiamo attivi il DNS (sulla porta 53, e sulla 32768 per la
+connessione di controllo del server \cmd{named}) ed un server DHCP (sulla
+porta 67).
+
+Si noti però come in questo caso la colonna che indica lo stato sia vuota. I
+socket UDP infatti non hanno uno stato. Inoltre anche in presenza di traffico
+non si avranno indicazioni delle connessioni attive, proprio perché non esiste
+niente di simile per i socket UDP, il kernel si limita infatti a ricevere i
+pacchetti ed inviarli al processo in ascolto sulla porta cui essi sono
+destinati, oppure a scartarli inviando un messaggio \textit{ICMP port
+  unreachable} qualora non vi sia nessun processo in ascolto.
 
 
 \subsection{Le funzioni \func{sendto} e \func{recvfrom}}
 \label{sec:UDP_sendto_recvfrom}
 
-Come accennato le due funzioni principali usate per la trasmissione di dati
-attraverso i socket UDP, ma in generale attraverso qualunque socket che
-preveda una comunicazione a pacchetti, sono \func{sendto} e \func{recvfrom}.
+Come accennato in \secref{sec:UDP_characteristics} le due funzioni principali
+usate per la trasmissione di dati attraverso i socket UDP, sono \func{sendto}
+e \func{recvfrom}. La necessità di usare queste funzioni è dovuta al fatto che
+non esistendo con UDP il concetto di connessione, non si ha neanche a
+disposizione un \textsl{socket connesso} su cui sia possibile usare
+direttamente \func{read} e \func{write} avendo già stabilito (grazie alla
+chiamata ad \func{accept} che lo associa ad una connessione) quali sono
+sorgente e destinazione dei dati.
+
+Per questo motivo nel caso di UDP diventa essenziale utilizzare queste due
+funzioni, che sono comunque usabili in generale per la trasmissione di dati
+attraverso qualunque tipo di socket, dato che esse hanno la caratteristica di
+provvedere tre argomenti aggiuntivi che consentono di specificare destinazione
+o origine dei dati trasmessi. La prima delle due funzioni è \funcd{sendto} ed
+il suo prototipo\footnote{il prototipo illustrato è quello utilizzato dalle
+  \acr{glibc}, che seguono le \textit{Single Unix Specification}, l'argomento
+  \param{flags} era di tipo \type{int} nei vari BSD4.*, mentre nelle
+  \acr{libc4} e \acr{libc5} veniva usato un \type{unsigned int}; l'argomento
+  \param{len} era \type{int} nei vari BSD4.* e nelle \acr{libc4}, ma
+  \type{size\_t} nelle \acr{libc5}; infine l'argomento \param{tolen} era
+  \type{int} nei vari BSD4.* nelle \acr{libc4} e nelle \acr{libc5}.} è:
+\begin{functions}
+  \headdecl{sys/types.h}
+  \headdecl{sys/socket.h}
+  
+  \funcdecl{ssize\_t sendto(int sockfd, const void *buf, size\_t len, int
+    flags, const struct sockaddr *to, socklen\_t tolen)}
+  
+  Trasmette un messaggio ad un altro socket.
+  
+  \bodydesc{La funzione restituisce il numero di caratteri inviati in caso di
+    successo e -1 per un errore; nel qual caso \var{errno} viene impostata al
+    rispettivo codice di errore:
+  \begin{errlist}
+  \item[\errcode{EAGAIN}] il socket è in modalità non bloccante, ma
+    l'operazione richede che la funzione si blocchi.
+  \item[\errcode{ECONNRESET}] l'altro capo della comunicazione ha resettato la
+    conessione.
+  \item[\errcode{EDESTADDRREQ}] il socket non è di tipo connesso, e non si è
+    specificato un indirizzo di destinazione.
+  \item[\errcode{EISCONN}] il socket è già connesso, ma si è specificato un
+    destinatario.
+  \item[\errcode{EMSGSIZE}] il tipo di socket richiede l'invio dei dati in un
+    blocco unico, ma la dimensione del messaggio lo rende impossibile.
+  \item[\errcode{ENOBUFS}] la coda di uscita dell'interfaccia è già piena (di
+    norma Linux non usa questo messaggio ma scarta silenziosamente i
+    pacchetti).
+  \item[\errcode{ENOTCONN}] il socket non è connesso e non si è specificata
+    una destinazione.
+  \item[\errcode{EOPNOTSUPP}] il valore di \param{flag} non è appropriato per
+    il tipo di socket usato.
+  \item[\errcode{EPIPE}] il capo locale della connessione è stato chiuso, si
+    riceverà anche un segnale di \const{SIGPIPE}, a meno di non aver impostato
+    \const{MSG\_NOSIGNAL} in \param{flags}.
+  \end{errlist}
+  ed anche \errval{EFAULT}, \errval{EBADF}, \errval{EINVAL}, \errval{EINTR},
+  \errval{ENOMEM}, \errval{ENOTSOCK} più gli eventuali altri errori relativi
+  ai protocolli utilizzati.}
+\end{functions}
+
+I primi tre argomenti sono identici a quelli della funzione \func{write} e
+specificano il socket \param{sockfd} a cui si fa riferimento ed il buffer
+\param{buf} (e relativa lunghezza \param{len}) che contiene i dati da inviare.
+Come per \func{write} la funzione ritorna il numero di byte inviati; nel caso
+di UDP però questo deve sempre corrispondere alla dimensione totale
+specificata da \param{len} in quanto i dati vengono sempre inviati in forma di
+pacchetto e non possono essere spezzati in invii successivi. Qualora non ci
+sia spazio nel buffer di uscita la funzione si blocca (a meno di non avere
+aperto il socket in modalità non bloccante), se invece non è possibile inviare
+il messaggio all'interno di un unico pacchetto essa fallisce con l'errore di
+\errcode{EMSGSIZE}.
+
+I due argomenti \param{to} e \param{tolen} servono a specificare la
+destinazione del messaggio da inviare, e prendono l'indirizzo di quest'ultima,
+nella stessa forma in cui lo si specificherebbe per \func{connect}: \param{to}
+deve cioè contere l'indirizzo IP e la porta di destinazione cui si vogliono
+inviare i dati e \param{tolen} la relativa dimensione. 
+
+Se il socket è di un tipo che prevede le connessioni, questo deve essere già
+connesso prima di eseguire la funzione (altrimenti si avrà un errore di
+\errcode{ENOTCONN}) ed inoltre questi due ultimi argomenti devono essere
+inizializzati rispettivamente a \const{NULL} e 0 (di solito vengono ignorati,
+ma si potrebbe ricevere altrimenti anche un errore di \errcode{EISCONN}).
+
+Infine l'argomento \param{flags} è un intero usato come maschera binaria che
+permette di impostare una serie di modalità di funzionamento della
+comunicazione attraverso il socket (come \const{MSG\_NOSIGNAL} che impedisce
+l'invio del segnale \const{SIGPIPE} quando si è già chiuso il capo locale
+della connessione). Torneremo con maggiori dettagli sul significato di questo
+argomento in \secref{sec:xxx_sendmsg}, per il momento ci si può limitare ad
+usare sempre un valore nullo.
+
+La seconda funzione utilizzata nella comunicazione fra socket UDP è
+\funcd{recvfrom} che serve invece a ricevere i dati inviati da un altro
+socket, il suo prototipo\footnote{il prototipo è quello delle \acr{glibc} che
+  seguono le \textit{Single Unix Specification}, i vari BSD4.*, le \acr{libc4}
+  e le \acr{libc5} usano un \type{int} come valore di ritorno; per gli
+  argomenti \param{flags} e \param{len} vale quanto detto a proposito di
+  \func{sendto}; infine l'argomento \param{fromlen} è \type{int} per i vari
+  BSD4.*, le \acr{libc4} e le \acr{libc5}.} è:
+\begin{functions}
+  \headdecl{sys/types.h}
+  \headdecl{sys/socket.h}
+  
+  \funcdecl{ssize\_t recvfrom(int sockfd, const void *buf, size\_t len, int
+    flags, const struct sockaddr *from, socklen\_t *fromlen)}
+  
+  Riceve un messaggio ad un altro socket.
+  
+  \bodydesc{La funzione restituisce il numero di byte ricevuti in caso di
+    successo e -1 in caso di errore; nel qual caso \var{errno} assumerà il
+    valore:
+  \begin{errlist}
+  \item[\errcode{EAGAIN}] il socket è in modalità non bloccante, ma
+    l'operazione richede che la funzione si blocchi, oppure si è impostato un
+    timeout in ricezione e questo è scaduto.
+  \item[\errcode{ECONNREFUSED}] l'altro capo della comunicazione ha rifiutato
+    la connessione (in genere perché il relativo servizio non è disponibile).
+  \item[\errcode{ENOTCONN}] il socket è di tipo connesso, ma non si è eseguita
+    la connessione.
+  \end{errlist}
+  ed anche \errval{EFAULT}, \errval{EBADF}, \errval{EINVAL}, \errval{EINTR},
+  \errval{ENOMEM}, \errval{ENOTSOCK} più gli eventuali altri errori relativi
+  ai protocolli utilizzati.}
+\end{functions}
+
+Come per \func{sendto} i primi tre argomenti sono identici agli analoghi di
+\func{read}: dal socket vengono letti \param{len} byte che vengono salvati nel
+buffer \param{buf}. A seconda del tipo di socket (se di tipo \textit{datagram}
+o \textit{stream}) inoltre i byte in eccesso che non sono stati letti possono
+rispettivamente andare persi o restare disponibili per una lettura
+successiva. 
+
+
+
+
+
+\subsection{L'uso della funzione \func{connect} con i socket UDP}
+\label{sec:UDP_connect}
+
+Come illustrato in \secref{sec:UDP_characteristics} essendo i socket UDP privi
+di connessione non è necessario per i client usare \func{connect} prima di
+iniziare una comunicazione con un server.
+
 
 
 \section{I socket \textit{Unix domain}}
-\label{sec:UDP_socket}
+\label{sec:unix_socket}
 
 Benché i socket Unix domain non siano strattamente attinenti alla rete, in
 quanto definiscono una interfaccia di comunicazione locale alla singola