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 c681fab8b6210ff6076a7828610cd616890d87e3..d44c6c38e47957ba1dfec004609f6dde29c48c4e 100644 (file)
Binary files a/img/udp_connection.dia and b/img/udp_connection.dia differ
index d7bc4c0e520f533aa96d408f139a64e35651097f..868ca66c247362706017f394bd3522e67860dce4 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
 \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
 
 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
 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
 
 \begin{figure}[htb]
   \centering
@@ -62,20 +66,200 @@ schema illustrato in \figref{fig:UDP_packet-exchange}.
   \label{fig:UDP_packet-exchange}
 \end{figure}
 
   \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}
 
 
 
 \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}}
 
 
 \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
 
 Benché i socket Unix domain non siano strattamente attinenti alla rete, in
 quanto definiscono una interfaccia di comunicazione locale alla singola