X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsock.tex;h=a976ecdc9b9e921b710555d94fc204056ccf9c15;hp=7316b64b3f274b7a3af14125b42fe7d9ffc31eb6;hb=ff76d56c6a2c280cbe4f153173488871d7b12336;hpb=1df343113e14ea885c3c3fdb985b2cb84230bd62 diff --git a/tcpsock.tex b/tcpsock.tex index 7316b64..a976ecd 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -1,6 +1,6 @@ %% tcpsock.tex %% -%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -8,6 +8,7 @@ %% license is included in the section entitled "GNU Free Documentation %% License". %% + \chapter{I socket TCP} \label{cha:TCP_socket} @@ -125,10 +126,14 @@ varr \subsection{Le opzioni TCP.} \label{sec:TCP_TCP_opt} -Ciascun segmento SYN contiene in genere delle opzioni per il protocollo TCP -(le cosiddette \textit{TCP options}, che vengono inserite fra l'header e i -dati) che servono a comunicare all'altro capo una serie di parametri utili a -regolare la connessione. Normalmente vengono usate le seguenti opzioni: +Ciascun segmento SYN contiene in genere delle opzioni per il protocollo TCP, +le cosiddette \textit{TCP options},\footnote{da non confondere con le opzioni + dei socket TCP che tratteremo in sez.~\ref{sec:sock_tcp_udp_options}, in + questo caso si tratta delle opzioni che vengono trasmesse come parte di un + pacchetto TCP, non delle funzioni che consentono di impostare i relativi + valori.} che vengono inserite fra l'header e i dati, e che servono a +comunicare all'altro capo una serie di parametri utili a regolare la +connessione. Normalmente vengono usate le seguenti opzioni: \begin{itemize} \item \textit{MSS option}, dove MMS sta per \itindex{Maximum~Segment~Size} @@ -136,7 +141,7 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: connessione annuncia all'altro il massimo ammontare di dati che vorrebbe accettare per ciascun segmento nella connessione corrente. È possibile leggere e scrivere questo valore attraverso l'opzione del socket - \const{TCP\_MAXSEG} (vedi sez.~\ref{sec:TCP_TCP_opt}). + \const{TCP\_MAXSEG} (vedi sez.~\ref{sec:sock_tcp_udp_options}). \item \textit{window scale option}, il protocollo TCP implementa il controllo di flusso attraverso una \itindex{advertised~window} \textit{advertised @@ -144,20 +149,29 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: sez.~\ref{sec:tcp_protocol_xxx}) con la quale ciascun capo della comunicazione dichiara quanto spazio disponibile ha in memoria per i dati. Questo è un numero a 16 bit dell'header, che così può indicare un massimo di - 65535 byte;\footnote{ Linux usa come massimo 32767 per evitare problemi con + 65535 byte;\footnote{Linux usa come massimo 32767 per evitare problemi con alcune implementazioni che usano l'aritmetica con segno per implementare lo stack TCP.} ma alcuni tipi di connessione come quelle ad alta velocità (sopra i 45Mbit/sec) e quelle che hanno grandi ritardi nel cammino dei pacchetti (come i satelliti) richiedono una finestra più grande per poter - ottenere il massimo dalla trasmissione, per questo esiste questa opzione che - indica un fattore di scala da applicare al valore della finestra - annunciata\footnote{essendo una nuova opzione per garantire la compatibilità - con delle vecchie implementazioni del protocollo la procedura che la - attiva prevede come negoziazione che l'altro capo della connessione - riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di - risposta dell'apertura della connessione.} per la connessione corrente - (espresso come numero di bit cui spostare a sinistra il valore della - finestra annunciata inserito nel pacchetto). + ottenere il massimo dalla trasmissione. Per questo esiste questa opzione che + indica un fattore di scala da applicare al valore della + \itindex{advertised~window} finestra annunciata\footnote{essendo una nuova + opzione per garantire la compatibilità con delle vecchie implementazioni + del protocollo la procedura che la attiva prevede come negoziazione che + l'altro capo della connessione riconosca esplicitamente l'opzione + inserendola anche lui nel suo SYN di risposta dell'apertura della + connessione.} per la connessione corrente (espresso come numero di bit cui + spostare a sinistra il valore della finestra annunciata inserito nel + pacchetto). Con Linux è possibile indicare al kernel di far negozioare il + fattore di scala in fase di creazione di una connessione tramite la + \textit{sysctl} \texttt{tcp\_window\_scaling} (vedi + sez.~\ref{sec:sock_ipv4_sysctl}).\footnote{per poter usare questa + funzionalità è comunque necessario ampliare le dimensioni dei buffer di + ricezione e spedizione, cosa che può essere fatta sia a livello di sistema + con le opportune \textit{sysct} (vedi sez.~\ref{sec:sock_ipv4_sysctl}) che + a livello di singoli socket con le relative opzioni (vedi + sez.~\ref{sec:sock_tcp_udp_options}).} \item \textit{timestamp option}, è anche questa una nuova opzione necessaria per le connessioni ad alta velocità per evitare possibili corruzioni di dati @@ -291,10 +305,10 @@ che il protocollo viene ad assumere per i due lati, server e client. \label{fig:TCP_conn_example} \end{figure} -La connessione viene iniziata dal client che annuncia una MSS -\itindex{Maximum~Segment~Size} di 1460, un valore tipico con Linux per IPv4 su -Ethernet, il server risponde con lo stesso valore (ma potrebbe essere anche un -valore diverso). +La connessione viene iniziata dal client che annuncia una +\itindex{Maximum~Segment~Size} MSS di 1460, un valore tipico con Linux per +IPv4 su Ethernet, il server risponde con lo stesso valore (ma potrebbe essere +anche un valore diverso). Una volta che la connessione è stabilita il client scrive al server una richiesta (che assumiamo stare in un singolo segmento, cioè essere minore dei @@ -720,9 +734,9 @@ Si noti che si \const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_} (riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo -l'\textit{endianess}\itindex{endianess} della macchina, ed anche se -esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque -buona norma usare sempre la funzione \func{htonl}. +\itindex{endianess} l'\textit{endianess} della macchina, ed anche se esse +possono essere invarianti rispetto all'ordinamento dei bit, è comunque buona +norma usare sempre la funzione \func{htonl}. \begin{table}[htb] \centering @@ -769,7 +783,7 @@ connessione con un server TCP,\footnote{di nuovo la funzione limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati e ricevuti i pacchetti, mentre per socket di tipo \const{SOCK\_STREAM} o \const{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del - TCP il \itindex{three~way~handshake}\textit{three way handshake}) della + TCP il \itindex{three~way~handshake} \textit{three way handshake}) della connessione.} il prototipo della funzione è il seguente: \begin{prototype}{sys/socket.h} {int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t @@ -814,11 +828,11 @@ nell'esempio sez.~\ref{sec:TCP_daytime_client}, usando le funzioni illustrate in sez.~\ref{sec:sock_addr_func}. Nel caso di socket TCP la funzione \func{connect} avvia il -\itindex{three~way~handshake}\textit{three way handshake}, e ritorna -solo quando la connessione è stabilita o si è verificato un errore. Le -possibili cause di errore sono molteplici (ed i relativi codici riportati -sopra), quelle che però dipendono dalla situazione della rete e non da errori -o problemi nella chiamata della funzione sono le seguenti: +\itindex{three~way~handshake} \textit{three way handshake}, e ritorna solo +quando la connessione è stabilita o si è verificato un errore. Le possibili +cause di errore sono molteplici (ed i relativi codici riportati sopra), quelle +che però dipendono dalla situazione della rete e non da errori o problemi +nella chiamata della funzione sono le seguenti: \begin{enumerate} \item Il client non riceve risposta al SYN: l'errore restituito è \errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla @@ -2028,7 +2042,7 @@ esaminato in sez.~\ref{sec:proc_termination}). In questo caso avremo l'invio del segnale \const{SIGCHLD} al padre, ma dato che non si è installato un gestore e che l'azione predefinita per questo segnale è quella di essere ignorato, non avendo predisposto la ricezione dello stato di terminazione, -otterremo che il processo figlio entrerà nello stato di zombie\index{zombie} +otterremo che il processo figlio entrerà nello stato di \index{zombie} zombie (si riveda quanto illustrato in sez.~\ref{sec:sig_sigchld}), come risulterà ripetendo il comando \cmd{ps}: \begin{verbatim} @@ -2036,7 +2050,7 @@ ripetendo il comando \cmd{ps}: 2359 pts/0 Z 0:00 [echod ] \end{verbatim} -Dato che non è il caso di lasciare processi zombie\index{zombie}, occorrerà +Dato che non è il caso di lasciare processi \index{zombie} zombie, occorrerà ricevere opportunamente lo stato di terminazione del processo (si veda sez.~\ref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo quanto illustrato in sez.~\ref{sec:sig_sigchld}. Una prima modifica al nostro @@ -2398,13 +2412,13 @@ dando il ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto. Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe -del \textit{three way handshake} \itindex{three~way~handshake} non avremo nulla -fin tanto che non scriveremo una prima riga sul client; al momento in cui -facciamo questo si genera una sequenza di altri quattro pacchetti. Il primo, -dal client al server, contraddistinto da una lettera \texttt{P} che significa -che il flag PSH è impostato, contiene la nostra riga (che è appunto di 11 -caratteri), e ad esso il server risponde immediatamente con un pacchetto vuoto -di ricevuto. Poi tocca al server riscrivere indietro quanto gli è stato +del \itindex{three~way~handshake} \textit{three way handshake} non avremo +nulla fin tanto che non scriveremo una prima riga sul client; al momento in +cui facciamo questo si genera una sequenza di altri quattro pacchetti. Il +primo, dal client al server, contraddistinto da una lettera \texttt{P} che +significa che il flag PSH è impostato, contiene la nostra riga (che è appunto +di 11 caratteri), e ad esso il server risponde immediatamente con un pacchetto +vuoto di ricevuto. Poi tocca al server riscrivere indietro quanto gli è stato inviato, per cui sarà lui a mandare indietro un terzo pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel client che lo stamperà a @@ -3202,8 +3216,8 @@ precedente versione causava l'immediato ritorno della funzione; in questo caso prima (\texttt{\small 19}) si imposta opportunamente \var{eof} ad un valore non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si -usa la macro \macro{FD\_CLR} per togliere lo standard input dal file -descriptor set. \itindex{file~descriptor~set} +usa la macro \macro{FD\_CLR} per togliere lo standard input dal +\itindex{file~descriptor~set} \textit{file descriptor set}. In questo modo anche se la lettura del file in ingresso è conclusa, la funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua @@ -3343,13 +3357,13 @@ vi sono dati sui socket connessi, per questo si ripete un ciclo diverso da zero; in questo modo se l'unico socket con attività era quello connesso, avendo opportunamente decrementato il contatore, il ciclo verrà saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del -\itindex{file~descriptor~set} file descriptor set con i nuovi valori nella -tabella) alla chiamata di \func{accept}. Se il socket attivo non è quello in -ascolto, o ce ne sono comunque anche altri, il valore di \var{n} non sarà -nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque si -inizializza (\texttt{\small 28}) il valore della variabile \var{i} che useremo -come indice nella tabella \var{fd\_open} al valore minimo, corrispondente al -file descriptor del socket in ascolto. +\itindex{file~descriptor~set} \textit{file descriptor set} con i nuovi valori +nella tabella) alla chiamata di \func{accept}. Se il socket attivo non è +quello in ascolto, o ce ne sono comunque anche altri, il valore di \var{n} non +sarà nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque +si inizializza (\texttt{\small 28}) il valore della variabile \var{i} che +useremo come indice nella tabella \var{fd\_open} al valore minimo, +corrispondente al file descriptor del socket in ascolto. Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore dell'indice \var{i} per posizionarsi sul primo valore possibile per un file @@ -3562,9 +3576,10 @@ uscita e notifica in caso si errore (\texttt{\small 49--52}). Come si può notare la logica del programma è identica a quella vista in fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la sola differenza significativa è che in questo caso non c'è bisogno di -rigenerare i \itindex{file~descriptor~set} file descriptor set in quanto -l'uscita è indipendente dai dati in ingresso. Si applicano comunque anche a -questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}. +rigenerare i \itindex{file~descriptor~set} \textit{file descriptor set} in +quanto l'uscita è indipendente dai dati in ingresso. Si applicano comunque +anche a questo server le considerazioni finali di +sez.~\ref{sec:TCP_serv_select}. % LocalWords: socket TCP client dell'I multiplexing stream three way handshake