From 6907e5e6ff5c69a34dc9d3664388cdb9f76ede82 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 21 Mar 2004 18:30:35 +0000 Subject: [PATCH] Messo esempio di server elementare. --- listati/UDP_daytimed.c | 47 +++++++++ othersock.tex | 212 ++++++++++++++++++++++++++++------------- sources/Makefile | 2 +- sources/UDP_daytimed.c | 136 ++++++++++++++++++++++++++ tcpsock.tex | 10 +- 5 files changed, 334 insertions(+), 73 deletions(-) create mode 100644 listati/UDP_daytimed.c create mode 100644 sources/UDP_daytimed.c diff --git a/listati/UDP_daytimed.c b/listati/UDP_daytimed.c new file mode 100644 index 0000000..f43853d --- /dev/null +++ b/listati/UDP_daytimed.c @@ -0,0 +1,47 @@ +int main(int argc, char *argv[]) +{ + int sock; + int i, n, len, verbose=0; + struct sockaddr_in addr; + char buffer[MAXLINE]; + time_t timeval; + ... + /* create socket */ + if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("Socket creation error"); + exit(-1); + } + /* initialize address */ + memset((void *)&addr, 0, sizeof(addr)); /* clear server address */ + addr.sin_family = AF_INET; /* address type is INET */ + addr.sin_port = htons(13); /* daytime port is 13 */ + addr.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ + /* bind socket */ + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind error"); + exit(-1); + } + /* write daytime to client */ + while (1) { + timeval = time(NULL); + n = recvfrom(sock, buffer, MAXLINE, 0, (struct sockaddr *)&addr, &len); + if (n < 0) { + perror("recvfrom error"); + exit(-1); + } + if (verbose) { + inet_ntop(AF_INET, &addr.sin_addr, buffer, sizeof(buffer)); + printf("Request from host %s, port %d\n", buffer, + ntohs(addr.sin_port)); + } + snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval)); + n = sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)); + if (n < 0) { + perror("sendto error"); + exit(-1); + } + } + /* normal exit */ + exit(0); +} diff --git a/othersock.tex b/othersock.tex index 7c7475c..00ee9c6 100644 --- a/othersock.tex +++ b/othersock.tex @@ -126,15 +126,15 @@ Per questo motivo nel caso di UDP diventa essenziale utilizzare queste due funzioni, che sono comunque utilizzabili in generale per la trasmissione di dati attraverso qualunque tipo di socket. Esse hanno la caratteristica di prevedere tre argomenti aggiuntivi attraveso i quali è possibile specificare -la destinazione o l'origine dei dati trasmessi. La prima di queste 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}.} è: +la destinazione dei dati trasmessi o ottenere l'origine dei dati ricevuti. La +prima di queste 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} @@ -176,42 +176,47 @@ la destinazione o l'origine dei dati trasmessi. La prima di queste funzioni I primi tre argomenti sono identici a quelli della funzione \func{write} e specificano il socket \param{sockfd} a cui si fa riferimento, il buffer -\param{buf} che contiene i dati da inviare e relativa lunghezza \param{len}. -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 (ad esempio perché eccede le -dimensioni massime del protocollo sottostante utilizzati) essa fallisce con -l'errore di \errcode{EMSGSIZE}. +\param{buf} che contiene i dati da inviare e la relativa lunghezza +\param{len}. 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 (ad esempio perché +eccede le dimensioni massime del protocollo sottostante utilizzato) 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 indicano rispettivamente la struttura -contentento l'indirizzo di quest'ultima e la relativa lunghezza. Questi -argomenti vanno specificati stessa forma in cui lo si userebbero con -\func{connect}: \param{to} deve cioè puntare alla struttura contenente -l'indirizzo IP e la porta di destinazione verso cui si vogliono inviare i dati -mentre \param{tolen} specifica la dimensione di quest'ultima. - -Se il socket è di un tipo che prevede le connessioni (ad esempio qualora si -usi la funzione con un socket TCP), questo deve essere già connesso prima di -eseguire la funzione, altrimenti si avrà un errore di \errcode{ENOTCONN}; -inoltre in questo caso gli argomenti \param{to} e \param{tolen} devono essere -inizializzati rispettivamente a \const{NULL} e 0 (di solito vengono ignorati, -ma si potrebbe anche ricevere 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. +contentente l'indirizzo di quest'ultima e la sua dimensione; questi argomenti +vanno specificati stessa forma in cui li si sarebbero usati con +\func{connect}. Nel nostro caso \param{to} devrà puntare alla struttura +contenente l'indirizzo IP e la porta di destinazione verso cui si vogliono +inviare i dati (questo è indifferente rispetto all'uso di TCP o UDP, usando +socket diversi si sarebbero dovute utilizzare le rispettive strutture degli +indirizzi). + +Se il socket è di un tipo che prevede le connessioni (ad esempio un socket +TCP), questo deve essere già connesso prima di poter eseguire la funzione, in +caso contrario si riceverà un errore di \errcode{ENOTCONN}. In questo +specifico caso in cui gli argomenti \param{to} e \param{tolen} non servono +essi devranno essere inizializzati rispettivamente a \const{NULL} e 0; +normalmente quando si opera su un socket conesso essi vengono ignorati, ma +qualora si sia specificato un indirizzo è possibile ricevere un errore di +\errcode{EISCONN}. + +Finora abbiamo tralasciato l'argomento \param{flags}; questo è 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}, dove +tratteremo le funzioni avanzate dei socket, 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 a ricevere i dati inviati da un altro socket, il +\funcd{recvfrom}, che serve 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 @@ -247,7 +252,7 @@ suo prototipo\footnote{il prototipo 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 +o di tipo \textit{stream}) i byte in eccesso che non sono stati letti possono rispettivamente andare persi o restare disponibili per una lettura successiva. Se non sono disponibili dati la funzione si blocca, a meno di non aver aperto il socket in modalità non bloccante, nel qual caso si avrà il solito errore di @@ -263,24 +268,25 @@ contenente quest'ultimo e la relativa lunghezza saranno scritti (si noti che argoment}). Se non si è interessati a questa informazione, entrambi gli argomenti devono essere inizializzati al valore \const{NULL}. -Un'altra differenza fondamentale di queste funzioni rispetto alle usuali -\func{read} e \func{write} che abbiamo usato con i socket TCP è che in questo -caso è perfettamente legale inviare con \func{sendto} un pacchetto vuoto (che -nel caso conterrà solo le intestazioni di IP e di UDP), scrivendo 0 byte. Allo -stesso modo è possibile ricevere con \func{recvfrom} un valore di ritorno di 0 -byte, senza che questo possa configurarsi come una chiusura della -connessione\footnote{dato che la connessione non esiste, non ha senso parlare - di chiusura della connessione, questo significa anche che con i socket UDP - non è necessario usare \func{close} o \func{shutdown} per terminare la - cominicazione.} o come una cessazione delle comunicazioni. +Una differenza fondamentale del comportamento di queste funzioni rispetto alle +usuali \func{read} e \func{write} che abbiamo usato con i socket TCP è che in +questo caso è perfettamente legale inviare con \func{sendto} un pacchetto +vuoto (che nel caso conterrà solo le intestazioni di IP e di UDP), +specificando un valore nullo per \param{len}. Allo stesso modo è possibile +ricevere con \func{recvfrom} un valore di ritorno di 0 byte, senza che questo +possa configurarsi come una chiusura della connessione\footnote{dato che la + connessione non esiste, non ha senso parlare di chiusura della connessione, + questo significa anche che con i socket UDP non è necessario usare + \func{close} o \func{shutdown} per terminare la cominicazione.} o come una +cessazione delle comunicazioni. -\subsection{Un client elementare} -\label{sec:UDP_simple_server} +\subsection{Un client UDP elementare} +\label{sec:UDP_daytime_client} Vediamo allora come implementare un primo client elementare con dei socket -UDP; ricalcando quanto fatto nel caso dei socket TCP prenderemo come primo +UDP. Ricalcando quanto fatto nel caso dei socket TCP prenderemo come primo esempio l'uso del servizio \textit{daytime}, utilizzando questa volta UDP. Il servizio è definito nell'\href{http://www.ietf.org/rfc/rfc0862.txt}{RFC~867}, che nel caso di uso di UDP prescrive che il client debba inviare un pacchetto @@ -295,13 +301,14 @@ sua volta un pacchetto UDP contenente la data. \normalsize \caption{Sezione principale del client per il servizio \textit{daytime} su UDP.} - \label{fig:UDP_daytime} + \label{fig:UDP_daytime_client} \end{figure} -In \figref{fig:UDP_daytime} è riportato la sezione principale del codice del -nostro client, il contenuto completo si trova nel file \file{UDP\_daytime.c} -dei sorgenti allegati; al solito si è tralasciata la gestione delle opzioni a -riga di comando (nel caso praticamente assenti). +In \figref{fig:UDP_daytime_client} è riportato la sezione principale del +codice del nostro client, il sorgente completo si trova nel file +\file{UDP\_daytime.c} distribuito con gli esempi allegati alla guida; al +solito si è tralasciato di riportare in figura la sezione relativa alla +gestione delle opzioni a riga di comando (nel caso praticamente assenti). Il programma inizia (\texttt{\small 9--12}) con la creazione del socket, al solito uscendo dopo aver stampato un messaggio in caso errore. Si noti come in @@ -334,16 +341,16 @@ si provvede (\texttt{\small 28}) ad invocare \func{recvfrom} per ricevere la risposta del server. Si controlla poi (\texttt{\small 29--32}) che non vi siano stati errori in ricezione (uscendo con un messaggio in caso contrario); se è tutto a posto la variabile \var{nread} conterrà la dimensione del -messaggio di risposta inviato dal server memorizzato su \var{buffer}, se -(\texttt{\small 34}) pertanto il valore è positivo si provvederà -(\texttt{\small 35}) a terminare la stringa contenuta nel buffer di +messaggio di risposta inviato dal server che è stato memorizzato su +\var{buffer}, se (\texttt{\small 34}) pertanto il valore è positivo si +provvederà (\texttt{\small 35}) a terminare la stringa contenuta nel buffer di lettura\footnote{si ricordi che, come illustrato in \secref{sec:TCP_daytime_client}, il server invia in risposta una stringa contenente la data, terminata dai due carratteri CR e LF, che pertanto prima - di essere stampata deve essere opportunamente terminata con NUL.} e a -stamparla (\texttt{\small 36}) sullo standard output, controllando -(\texttt{\small 36--38}) anche in questo caso l'esito dell'operazione ed -uscendo in caso di errore. + di essere stampata deve essere opportunamente terminata con un NUL.} e a +stamparla (\texttt{\small 36}) sullo standard output, controllando anche in +questo caso (\texttt{\small 36--38}) l'esito dell'operazione, ed uscendo con +un messaggio in caso di errore. Se pertanto si è avuto cura di attivare il server del servizio \textit{daytime}\footnote{di norma questo è un servizio standard fornito dal @@ -363,7 +370,78 @@ server: tcpdump: listening on lo 23:41:21.645579 localhost.32780 > localhost.daytime: udp 0 (DF) 23:41:21.645710 localhost.daytime > localhost.32780: udp 26 (DF) -\end{verbatim} +\end{verbatim} + +Una differenza fondamentale del nostro client è che in questo caso, non +disponendo di una connessione, è per lui impossibile riconoscere errori di +invio relativi alla rete. La funzione \func{sendto} infatti riporta solo +errori locali, i dati vengono comunque scritti e la funzione ritorna senza +errori anche se il server non è raggiungibile o non esiste un server in +ascolto sull'indirizzo di destinazione. Questo comporta ad esempio che se si +usa il nostro programma interrogando un server inesistente questo resterà +perennemente bloccato nella chiamata a \func{recvfrom}, fin quando non lo +interromperemo. Vedremo in \secref{sec:UDP_connect} come si può porre rimedio +a questa problematica. + + + +\subsection{Un server UDP elementare} +\label{sec:UDP_daytime_server} + +Nella sezione precedente abbiamo visto come scrivere un client elementare per +servizio \textit{daytime}, vediamo in questa come deve essere scritto un +server. Si ricordi che il compito di quest'ultimo è quello di ricevere un +pacchetto di richiesta ed inviare in risposta un pacchetto contenente una +stringa con la data corrente. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/UDP_daytimed.c} + \end{minipage} + \normalsize + \caption{Sezione principale del server per il servizio \textit{daytime} su + UDP.} + \label{fig:UDP_daytime_server} +\end{figure} + +In \figref{fig:UDP_daytime_server} è riportato la sezione principale del +codice del nostro client, il sorgente completo si trova nel file +\file{UDP\_daytimed.c} distribuito con gli esempi allegati alla guida; anche +in questo caso si è omessa la sezione relativa alla gestione delle opzioni a +riga di comando (la sola presente è \texttt{-v} che permette di stampare a +video l'indirizzo associato ad ogni richiesta). + +Anche in questo caso la prima parte del server (\texttt{\small 9--23}) è +sostanzialmente identica a quella dell'analogo server per TCP illustrato in +\figref{fig:TCP_daytime_cunc_server_code}; si inizia (\texttt{\small 10}) con +il creare il socket, uscendo con un messaggio in caso di errore +(\texttt{\small 10--13}), e di nuovo la sola differenza con il caso precedente +è il diverso tipo di socket utilizzato. Dopo di che (\texttt{\small 14--18}) +si inizializza la struttura degli indirizzi che poi (\texttt{\small 20}) verrà +usata da \func{bind}; si cancella (\texttt{\small 15}) preventivamente il +contenuto, si imposta (\texttt{\small 16}) la famiglia dell'indirizzo, la +porta (\texttt{\small 17}) e l'indirizzo (\texttt{\small 18}) su cui si +riceveranno i pacchetti. Si noti come in quest'ultimo sia l'indirizzo +generico \const{INADDR\_ANY}; questo significa (si ricordi quanto illustrato +in \secref{sec:TCP_func_bind}) che il server accetterà pacchetti su uno +qualunque degli indirizzi presenti sulle interfacce di rete della macchina. + +Completata l'inizializzazione tutto quello che resta da fare è eseguire +(\texttt{\small 20--23}) la chiamata a \func{bind}, controllando la presenza +di eventuali errori, ed uscendo con un avviso qualora questo fosse il caso. +Nel caso di socket UDP questo è tutto quello che serve per consentire al +server di ricevere i pacchetti a lui indirizzati, e non è più necessario +chiamare successivamente \func{listen}. In questo caso infatti non esiste il +concetto di connessione, e quindi non deve essere predisposta una coda delle +connessioni entranti. Nel caso di UDP i pacchetti arrivano al kernel con un +certo indirizzo ed una certa porta di destinazione, il kernel controlla se +corrispondono ad un socket che è stato \textsl{legato} ad essi con +\func{bind}, qualora questo sia il caso scriverà il contenuto all'interno del +socket, così che il programma possa leggerlo, altrimenti risponderà alla +macchina che ha inviato il pacchetto con un messaggio ICMP di tipo +\textit{port unreachable}. + diff --git a/sources/Makefile b/sources/Makefile index f9ea4bb..b620e0c 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -79,7 +79,7 @@ sechod: select_echod.c pechod: poll_echod.c $(CC) $(CFLAGJ) $(CFLAGS) $^ -o $@ -daytimed: TCP_cunc_daytimed.c +daytimed: UDP_daytimed.c # TCP_cunc_daytimed.c $(CC) $(CFLAGJ) $^ -o $@ iterdaytimed: TCP_iter_daytimed.c diff --git a/sources/UDP_daytimed.c b/sources/UDP_daytimed.c new file mode 100644 index 0000000..4a7e034 --- /dev/null +++ b/sources/UDP_daytimed.c @@ -0,0 +1,136 @@ +/* UDP_daytimed.c + * + * Copyright (C) 2004 Simone Piccardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/**************************************************************** + * + * Program daytimed: + * Elementary TCP server for daytime service (port 13) + * + * Author: Simone Piccardi + * Mar. 2004 + * + * Usage: daytimed -h give all info + * + * $Id: UDP_daytimed.c,v 1.1 2004/03/21 18:30:35 piccardi Exp $ + * + ****************************************************************/ +/* + * Include needed headers + */ +#include /* predefined types */ +#include /* include unix standard library */ +#include /* IP addresses conversion utiliites */ +#include /* socket library */ +#include /* include standard I/O library */ +#include + +#define MAXLINE 80 +/* Program begin */ +void usage(void); +int main(int argc, char *argv[]) +{ +/* + * Variables definition + */ + int sock; + int i, n, len, verbose=0; + struct sockaddr_in addr; + char buffer[MAXLINE]; + time_t timeval; + /* + * Input section: decode parameters passed in the calling + * Use getopt function + */ + opterr = 0; /* don't want writing to stderr */ + while ( (i = getopt(argc, argv, "hv")) != -1) { + switch (i) { + /* + * Handling options + */ + case 'h': + printf("Wrong -h option use\n"); + usage(); + return(0); + break; + case 'v': + verbose = 1; + break; + case '?': /* unrecognized options */ + printf("Unrecognized options -%c\n",optopt); + usage(); + default: /* should not reached */ + usage(); + } + } + /* *********************************************************** + * + * Options processing completed + * + * Main code beginning + * + * ***********************************************************/ + /* create socket */ + if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("Socket creation error"); + exit(-1); + } + /* initialize address */ + memset((void *)&addr, 0, sizeof(addr)); /* clear server address */ + addr.sin_family = AF_INET; /* address type is INET */ + addr.sin_port = htons(13); /* daytime port is 13 */ + addr.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ + /* bind socket */ + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind error"); + exit(-1); + } + /* write daytime to client */ + while (1) { + timeval = time(NULL); + n = recvfrom(sock, buffer, MAXLINE, 0, (struct sockaddr *)&addr, &len); + if (n < 0) { + perror("recvfrom error"); + exit(-1); + } + if (verbose) { + inet_ntop(AF_INET, &addr.sin_addr, buffer, sizeof(buffer)); + printf("Request from host %s, port %d\n", buffer, + ntohs(addr.sin_port)); + } + snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval)); + n = sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)); + if (n < 0) { + perror("sendto error"); + exit(-1); + } + } + /* normal exit */ + exit(0); +} +/* + * routine to print usage info and exit + */ +void usage(void) { + printf("Simple daytime server\n"); + printf("Usage:\n"); + printf(" daytimed [-hv] \n"); + printf(" -h print this help\n"); + printf(" -v print request source on stdout\n"); + exit(1); +} diff --git a/tcpsock.tex b/tcpsock.tex index 5ddcd16..03955c5 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -682,11 +682,11 @@ per il server\footnote{un'eccezione a tutto ci cui risponde (l'elenco di queste porte, e dei relativi servizi, è in \file{/etc/services}). -Con \func{bind} si può assegnare un IP specifico ad un socket, purché questo -appartenga ad una interfaccia della macchina. Per un client TCP questo -diventerà l'indirizzo sorgente usato per i tutti i pacchetti inviati sul -socket, mentre per un server TCP questo restringerà l'accesso al socket solo -alle connessioni che arrivano verso tale indirizzo. +Con \func{bind} si può assegnare un indirizzo IP specifico ad un socket, +purché questo appartenga ad una interfaccia della macchina. Per un client TCP +questo diventerà l'indirizzo sorgente usato per i tutti i pacchetti inviati +sul socket, mentre per un server TCP questo restringerà l'accesso al socket +solo alle connessioni che arrivano verso tale indirizzo. Normalmente un client non specifica mai l'indirizzo di un socket, ed il kernel sceglie l'indirizzo di origine quando viene effettuata la connessione, sulla -- 2.30.2