Vous êtes sur la page 1sur 139

La tabella riporta una classificazione dei vari tipi di rete, in

funzione dellambito operativo e delle distanze coperte.


AMBITO DISTANZA RETE
COPERTA
Edificio 100 m Reti Locali (LAN)
Comprensorio 1 km Reti Locali (LAN)
Citt 10 km Reti Metropolitane (MAN)
Nazione 100 km Reti Geografiche (WAN)
Continente 1000 km Reti Geografiche (WAN)
Pianeta 10000 km Reti Geografiche (WAN)
La figura qui sopra riporta la struttura di una rete di calcolatori
di una ipotetica azienda. Essa formata da una rete locale
(LAN: Local Area Network) in ogni sede (edificio) della
azienda; le LAN presenti allinterno di unarea metropolitana
sono collegate tra loro tramite MAN (Metropolitan Area
Network) e queste a loro volta tramite una rete geografica
(WAN: Wide Area Network).
Una Tassonomia delle Reti
2
LAN LAN LAN LAN LAN
MAN
WAN
Un esempio di Wan:
la rete dellUniversit di Bologna
3
Rimini
Ravenna
Forl
Bologna
M. Maggio
Monte
Calderaro
Cesena
Bertinoro
Ozzano
Le RETI LOCALI (LAN).
Una rete locale un mezzo di trasporto equamente condiviso
tra tutte le stazioni che vi si collegano, ad alta velocit e basso
tasso derrore, limitato ad un ambito locale.
Le velocit trasmissive sono comprese nellintervallo 4 Mb/s -
155 Mb/s. Accanto alle vecchie reti Ethernet e Token Ring si
sono aggiunte reti pi moderne quali FastEthernet a 100 Mb/s e
ATM a 34 e 155 Mb/s.
Tutte queste tecnologie adottano tipicamente come supporto
trasmissivo preferenziale il doppino di rame e la fibra ottica
sulle dorsali. Il cavo coassiale stato (per fortuna) quasi del
tutto abbandonato.
Le RETI METROPOLITANE (MAN).
Sono recenti estensioni delle reti locali in ambito urbano.
Sfruttano una grande variet di tecnologie, che vanno dai ponti
radio ad alta frequenza (es ponti radio punto-punto a 38 GHz
per velocit da 2 Mb/s a 34 Mb/s, o punto-multipunto di tipo
Spread Spectrum) alle fibre ottiche.
Le prestazioni classiche raggiunte sono comprese tra 2 Mb/s e
155 Mb/s.
Le RETI GEOGRAFICHE (WAN).
Si basano solitamente su servizi offerti dai gestori nazionali di
telecomunicazione, che rendono disponibili canali per
trasmissione digitale punto a punto, i cosiddetti CDN (Canali
Diretti Numerici). Acausa della liberalizzazione del mercato
lofferta in continua evoluzione.
Caratteristiche delle Reti
4
L OSI un progetto di ampio respiro formulato dallISO
(International Standard Organization) alla fine degli anni 70
con lo scopo di fungere da modello di riferimento per le reti di
calcolatori.
LISO doveva:
standardizzare la terminologia;
definire quali sono le funzionalit di una rete;
servire come base comune da cui far partire lo sviluppo di
standard per linterconnessione di sistemi informatici;
fornire un modello rispetto a cui confrontare le architetture di
reti proprietarie.
Per gestire la complessit dei problemi, lOSI ha adottato un
approccio a livelli (layers): il problema della comunicazione tra
due applicazioni stato spezzato in un insieme di 7 livelli,
ciascuno dei quali esegue funzioni ben specifiche.
LOSI ha cercato di diventare pi di un modello di riferimento.
Infatti lISO ha standardizzato per OSI una serie di protocolli,
da collocare nei vari livelli del modello, per formare una vera
architettura di rete concorrenziale con altre, quali lo Stack
TCP/IP.
I livelli 1 (Fisico) e 2 (Data Link) sono stati accettati e sono
oggi degli standard, garantendo linteroperabilit dei prodotti.
I protocolli di livello superiore incontrano pi difficolt a causa
dellalto impatto che la loro adozione avrebbe sui dispositivi di
instradamento e sul software dei sistemi informativi.
LOSI (Open System Interconnections)
5
Per ridurre la complessit del progetto, OSI introduce
unarchitettura a livelli (layered architecture) i cui componenti
principali sono:
i livelli (layers)
le entit (entities)
i punti di accesso al servizio (SAP: Service Access Points)
le connessioni (connections)
In tale architettura, ciascun sistema decomposto in un insieme
ordinato di livelli, rappresentati per convenienza come una pila
verticale. La figura seguente rappresenta i livelli che
compongono il modello di riferimento ISO-OSI.
Tale approccio di progettazione a livelli comune a tutte le
moderne architetture di rete.
Il modello ISO/OSI
Architettura a Livelli
6
Anche se definito un protocollo di livello N, nessun dato
trasferito direttamente da un livello Nallaltro su un diverso
sistema.
Infatti ogni livello passa dati e informazioni di controllo a
quello sottostante, sino a quando si giunge al livello Fisico, che
effettua la trasmissione verso laltro sistema.
Linterfaccia di un livello definisce quali operazioni primitive
e quali servizi sono forniti da un livello ai livelli superiori.
In figura rappresentato il meccanismo di comunicazione tra due entit
di livello N= 4, con il messaggio che viene passato via via ai livelli
inferiori (che aggiungono i loro header), viene trasmesso attraverso il
mezzo fisico, e giunto al sistema di destinazione risale liberandosi degli
header aggiunti, fino ad arrivare al livello stabilito.
Il modello ISO/OSI
Comunicazioni tra livelli su sistemi diversi (2)
9
Il livello 1: FISICO.
Il livello 1 del modello OSI si occupa di trasmettere sequenze
binarie sul canale di comunicazione. Aquesto livello si
specificano ad esempio le tensioni che rappresentano 0 e 1 e le
caratteristiche dei cavi e dei connettori.
Il livello 2: DATA LINK.
Il livello ha come scopo la trasmissione sufficientemente
affidabile di pacchetti detti frame tra due sistemi contigui.
Accetta come input dei pacchetti di livello 3 (tipicamente poche
centinaia di bit) e li trasmette sequenzialmente. Esso verifica la
presenza di errori aggiungendo delle FCS (Frame Control
Sequence) e pu gestire meccanismi di correzione di tali errori
tramite ritrasmissione.
Il livello 3: NETWORK.
Il livello 3 il livello Network, che gestisce linstradamento dei
messaggi, ed il primo livello (a partire dal basso) che gestisce
informazioni sulla topologia della rete. Tale livello determina se
e quali sistemi intermedi devono essere attraversati dal
messaggio per giungere a destinazione. Deve quindi gestire
delle tabelle di instradamento e provvedere ad instradamenti
alternativi in caso di guasti (fault tollerance).
Il modello ISO/OSI
I Livelli (1)
7
Il livello 4: TRASPORTO.
Il livello 4 del modello OSI fornisce un servizio di trasferimento
trasparente dei dati tra entit del livello 5 (sessione). Si occupa
di garantire un servizio affidabile. Deve quindi effettuare la
frammentazione dei dati, la correzione degli errori e la
prevenzione della congestione della rete. Il livello 4 il livello
pi basso, a partire dallalto, a trascurare la topologia della rete
e la presenza di sistemi intermedi di instradamento, ed quindi
detto livello end-to-end.
Il livello 5: SESSIONE.
Organizza il dialogo tra due programmi applicativi, consentendo
di aggiungere a connessioni end-to-end servizi pi avazati.
Il livello 6: PRESENTAZIONE.
Definisce formalmente i dati che gli applicativi si scambiano,
come questi dati sono rappresentati localmente sul sistema, e
come vengono codificati durante il trasferimento.
Il livello 7: APPLICAZIONE.
Il livello 7 il livello dei programmi applicativi, facenti parte
del sistema operativo oppure scritti dallutente, attraverso i quali
lutente utilizza la rete.
Il modello ISO/OSI
I Livelli (2)
8
Linsieme dei livelli, dei protocolli e delle interfacce definisce
unarchitettura di rete. Le architetture di rete pi note sono:
SNA (System Network Architecture) architettura della rete
IBM;
DNA (Digital Network Architecture), meglio nota come
DECnet, la rete della Digital Equipment Corporation;
Internet protocol Suite, meglio nota con il nome TCP/IP, la
rete degli elaboratori UNIX e rappresenta uno standard de
facto attualmente impiegato per la rete Internet.
OSI (Open System Architecture), che lo standard de iure
prodotto dallISO.
Principali Architetture di Rete
10
La trasmissione dei dati avviene quindi:
attraverso una serie di passaggi da livelli superiori a livelli
inferiori nel sistema che trasmette,
poi attraverso mezzi fisici di comunicazione,
infine attraverso unaltra serie di passaggi, questa volta da
livelli inferiori a livelli superiori.
Notare come a livello 2, sia necessario aggiungere in coda un
campo che identifica la fine del pacchetto prima di passare lo
stesso al livello che utilizza il mezzo trasmissivo.
Incapsulamento dei Pacchetti
11
Non sempre lo scambio delle informazioni avviene direttamente
tra i due sistemi finali che contengono le applicazioni (ES: End
Systems). Pu anche implicare lattraversamento di alcuni
sistemi intermedi (IS: Intermediate Systems).
In questi Intermediate Systems esistono delle entit che
assumono la funzione di Router (in senso esteso), ovvero entit
che instradano le informazioni.
Tali entit possono essere collocate a diversi livelli del modello
OSI, ed allora gli Intermediate Systems assumono nomi diversi
a seconda del livello in cui avviene linstradamento dei dati. Si
parla allora di repeater a livello 1, bridge a livello 2, router a
livello 3 ed infine gateway a livello 7.
Qui di seguito rappresentata la collocazione di un Router nel
modello OSI.
Sistemi Intermedi (1)
12
Accenniamo per ora solo allazione svolta dai Repeater, mentre
linstradamento a livelli superiori, che comporta anche la
rigenerazione digitale del segnale, sar approfondito
analizzando lo stack TCP/IP
Qui di seguito rappresentata la collocazione di un Repeater nel
modello OSI. Il livello Fisico non effettua correzione dei dati
ricevuti, compito che invece spetta al livello Data Link.
Il segnale che il Repeater riceve da un lato viene amplificato e
propagato allaltro lato, quindi viene propagato anche il rumore
che pu essersi prodotto durante la trasmissione dal sistema A al
Repeater, e a tale rumore si aggiunger il rumore prodotto nella
trasmissione dal Repeater al sistema B.
Di conseguenza il livello Fisico del sistema B riceve un segnale
afflitto dalla somma dei rumori che si sono prodotti durante la
trasmissione sui due tratti di percorso, e quindi aumenta la
probabilit che si riscontri un errore nei dati trasmessi.
La correzione potr essere effettuata solo quando il segnale
giunger al sistema 2, ma leventuale ritrasmissione dei dati
dovr attraversare nuovamente i due tratti di rete.
E per questo motivo che bisogna ridurre al minimo il numero
di repeater in un percorso.
Sistemi Intermedi (2)
13
14
Architettura TCP/IP e confronto con OSI
15
Interfaccia Socket
I livelli TCP/IP hanno questa relazione con i livelli di OSI.
Lo stack di protocolli TCP/IP implementa un livello network
(livello 3) di tipo:
packet-switched;
connectionless.
Il livello pi basso (corrispondente ai livelli 1 e 2 di OSI) non
specificato dallarchitettura, che prevede di utilizzare quelli
disponibili per le varie piattaforme HW e conformi agli
standard.
Per quanto riguarda le reti in ambito locale (LAN), lo standard
riconosciuto per i livelli 1 e 2 rappresentato dal progetto IEEE
802, che stato riconosciuto anche da OSI.
Per capire il funzionamento dei protocolli TCP/IP, nel seguito
considereremo proprio la situazione di una rete locale. Risulta
necessario perci soffermarsi brevemente sulla strutturazione
delle LAN.
Lo Stack TCP/IP: Le Basi
30
DEFINIZIONE: una LAN un sistema di comunicazione che
permette ad apparecchiature indipendenti di comunicare tra loro,
entro un area delimitata, utilizzando un canale fisico a velocit
elevata e con basso tasso d`errore.
Le LAN hanno quindi sempre un solo canale trasmissivo ad
alta velocit condiviso nel tempo da tutti i sistemi collegati.
Quando un sistema trasmette diventa proprietario
temporaneamente (per la durata di uno o pochi pacchetti)
dell'intera capacit trasmissiva della rete.
La trasmissione sempre di tipo broadcast, ovvero un sistema
trasmette e tutti gli altri ricevono. Tale organizzazione ha
enormi vantaggi, ma impone anche alcune complicazioni:
necessaria la presenza di indirizzi di livello 2 per stabilire chi
sono il reale destinatario e il mittente della trasmissione e
occorre arbitrare l'accesso all'unico mezzo trasmissivo tra tutti i
sistemi che hanno necessit di trasmettere.
L'unico canale trasmissivo presente deve anche essere
caratterizzato da un basso tasso di errore. Questo ottenibile
abbastanza facilmente in un'area delimitata usando mezzi
trasmissivi di buona qualit. L'effetto ottenuto quello che le
LAN, essendo intrinsecamente affidabili, non hanno la necessit
di correggere gli errori a livello 2 OSI e quindi normalmente
utilizzano protocolli di livello 2 connectionless ad alte
prestazioni.
Le LAN (Local Area Network)
31
Quando le prime LAN cominciarono a diffondersi lIEEE decise di
costituire sei comitati per studiare il problema della
standardizzazione delle LAN e delle MAN, complessivamente
raccolti nel progetto IEEE 802. IEEE 802 introduce lidea che le
LAN e le MAN devono fornire un'interfaccia unificata verso il
livello Network (livello rete), pur utilizzando tecnologie
trasmissive differenziate. Per ottenere tale risultato, il progetto
IEEE 802 suddivide il livello Data Link in due sottolivelli:
LLC (Logical Link Control);
MAC (Media Access Control).
Il sottolivello LLC comune a tutte le LAN, mentre il MAC
caratteristico di ciascuna LAN, cos come il livello fisico al
quale strettamente associato. Il sottolivello LLC l'interfaccia
unificata verso il livello Network ed descritto nell'apposito
standard IEEE 802.2, mentre i vari MAC sono descritti negli
standard specifici di ogni rete locale (ad esempio il MAC
CSMA/CD descritto nello standard IEEE 802.3, ed il MAC Fast
Ethernet (100BaseT) descritto in IEEE 802.3u).
32
Il Progetto IEEE 802
Il sottolivello MAC specifico di ogni LAN e risolve il
problema della condivisione del mezzo trasmissivo.
Il MAC indispensabile in quanto a livello 2 (Data Link) le
LAN implementano sempre una sottorete trasmissiva di tipo
broadcast in cui ogni sistema riceve tutti i frame inviati dagli
altri.
Per trasmettere in broadcast, cio far condividere un unico
canale trasmissivo a tutti i sistemi, bisogna risolvere due
problemi:
in trasmissione, verificare che il canale sia libero prima di
trasmettere e risolvere eventuali conflitti di pi sistemi che
vogliano utilizzare contemporaneamente il canale;
in ricezione, determinare a quali sistemi effettivamente
destinato il messaggio e quale sistema lo ha generato.
La soluzione del primo problema data dai vari algoritmi di
MAC, basati su principi diversi, quali la contesa, il token, la
prenotazione e il round-robin.
La soluzione del secondo problema necessita della presenza di
indirizzi a livello MAC (quindi nella MAC-PDU) che
identifichino ciascun sistema e trasformino trasmissioni
broadcast in:
tramissioni punto-punto, se l'indirizzo di destinazione indica
un singolo sistema;
trasmissioni punto-gruppo, se l'indirizzo di destinazione
indica un gruppo di sistemi;
trasmissioni effettivamente broadcast, se l'indirizzo di
destinazione indica tutti i sistemi.
MAC: Media Access Control (1)
33
Quando una scheda di rete locale riceve un pacchetto, questo
non viene passato automaticamente al livello superiore (LLC)
ma viene analizzato a livello MAC, per effettuare una serie di
controlli.
Per prima cosa il MAC verifica che il pacchetto sia integro (cio
abbia una FCS Frame Control Sequence corretta) e di
dimensioni ammesse.
Successivamente il livello MAC analizza l'indirizzo di
destinazione (MAC-DSAP).
Si possono porre tre casi:
se lindirizzo MAC di destinazione (il MAC-DSAP)
broadcast, il pacchetto viene sempre passato al LLC, perch
tutti i sistemi devono riceverlo;
se il MAC-DSAP single, il pacchetto viene passato al LLC
solo se il MAC-DSAP uguale all'indirizzo hardware della
scheda o a quello caricato da software nell'apposito buffer;
se il MAC-DSAP multicast, si verifica se la ricezione di quel
multicast stata abilitata dal software di livello superiore, cio di
livello 3, cio se la scheda appartiene al gruppo indirizzato.
Poich non noto a priori a quanti gruppi possa appartenere una
scheda, si usano delle tecniche di hash per mantenere la lista dei
gruppi abilitati.
Gli indirizzi di gruppo servono principalmente per scoprire quali
altri sistemi sono collegati alla rete locale, quali servizi questi
mettono a disposizione e, molto importante, le relazioni
esistenti tra gli indirizzi MAC e gli indirizzi di livello 3.
Ricezione dei Pacchetti a livello 2
36
Nel modo normale visto nella precedente slide, se una scheda di
rete inserita in una LAN riceve un pacchetto, lo passa al livello
superiore (LLC) solo se il pacchetto di livello MAC un
pacchetto broadcast, o un pacchetto single con indirizzo uguale
a quello della scheda di rete, o un pacchetto multicast con
indirizzo con cui unindirizzo dellhost in corrispondenza.
In tal modo si ha la garanzia che i pacchetti destinati ad un host
vengano letti solo da quellhost.
In realt esiste unaltra modalit di funzionamento delle schede
di rete per LAN, detto modo promiscuo (promiscuous
mode) in cui tutti i pacchetti ricevuti a livello MAC sono passati
ai livelli superiori. In tal caso lanalisi sulla destinazione dei
pacchetti dovr essere effettuata da protocolli di livello
superiore.
Tale modalit di funzionamento viene utilizzata da applicazioni
(ad es. il tcpdump per Linux) per effettuare il monitoraggio
della rete, ovvero per controllare quanti e quali pacchetti
vengono trasmessi in rete, da chi, ecc.. .
Ovviamente tale modalit rappresenta un problema di sicurezza
perch rende possibile vedere dati riservati trasmessi via rete.
Per tale motivo i sistemi operativi moderni permettono solo
allamministratore del sistema (root) di configurare la scheda di
rete perch funzioni in modo promiscuo, impedendo ad altri di
accedere alla porta attraverso la quale si configura la
scheda di rete.
Ricezione dei Pacchetti a livello 2
Uneccezione: il modo PROMISCUO
37
I concetti di indirizzi single, multicast e broadcast sono
implementati sia a livello MAC che a livello IP.
Unapplicazione importantissima del meccanismo di broadcast
realizzato a livello MAC, rappresentato dal protocollo ARP di
(livello 3) del TCP/IP, che permette ad un host S su una certa LAN,
di scoprire a partire dallindirizzo IP dellhost di destinazione D (se
questo sta nella stessa LAN), lindirizzo MAC dellhost
destinazione stesso, indirizzo che servir per inviare il frame che
incapsuler il pacchetto destinato allhost di destinazione. !!!
Il protocollo ARP opera in questo modo:
lhost S invia a tutte le stazioni della LAN, in data link broadcast,
una richiesta del tipo: "chi ha l'indirizzo IP uguale a IP_D ?.
tutti gli host ricevono la risposta, e i MAC la passano a livello 3.
solo l'host che ha quell'indirizzo IP IP_D risponde, inserendo
nella risposta il proprio indirizzo MAC;
quando S riceve la risposta, sa a che MAC address deve inviare il
pacchetto.
l'host S mantiene in memoria il MAC address di D per alcuni
minuti, per eventuali trasmissioni successive.
A livello IP il multicast utilizzato per realizzare con semplicit dei
flussi di comunicazione punto-multipunto, che sono sfruttati ad es.
in applicazioni di videoconferenza, quali ad es. MBone. In tali
applicazioni un singolo pacchetto inviato dal sorgente raggiunge
molti hosts destinatari, duplicandosi opportunamente quando i
percorsi si dividono.
Utilizzo del Broadcast.
38
Qualche considerazione:
Ogni interfaccia di rete locale gestita da un suo livello MAC.
Su tale livello MAC si appoggia un livello LLC.
Il livello MAC implementato nell'hardware della scheda di rete
locale, mentre il livello LLC di solito realizzato in software.
Ogni livello LLC pu gestire un solo livello MAC: questo
significa che un livello LLC non pu avere funzionalit di
"relaying" (non pu inoltrare pacchetti) tra pi MAC.
Tale funzionalit di instradamento dei pacchetti delegata
al livello 3.
In figura vediamo le relazioni tra le Protocol Data Unit di livello
3 (Network), le LLC-PDU e le MAC-PDU, incapsulate una
dentro laltra. Notare come ogni livello specifichi due indirizzi
di quel livello, un mittente (*-SSAP, S come Source) ed un
destinatario (*-DSAP, D come Destination) per i
pacchetti/frame passati al livello inferiore.
Relazione tra il Livello 3, Logical Link
Control e Media Access Control.
39
LLC ha lo scopo di fornire uninterfaccia unificata con il livello
network, e di fornire un supporto standard alla convivenza di
pi protocolli di livello superiore sulla stessa LAN.
Proprio per questo scopo la Protocol Data Unit di LLC contiene
anchessa due indirizzi, una destinazione e una sorgente, e questi
indirizzi rappresentano gli identificatori del protocollo di livello
superiore a cui il livello LLC deve consegnare il pacchetto che
gli arrivato [o da cui il pacchetto arrivato] .
LLC: Logical Link Control
Destination
Address
Source
Address
L3-Information Control
Supporto multiprotocollo offerto da LLC
La PDU di LLC
40
Il campo Options non necessario in tutti i datagram IP. Le opzioni
sono utilizzate allo scopo di testare la funzionalit della rete sottostante.
Evitiamo di addentrarci su come sono organizzati i sottocampi del
campo Opzioni IP, e analizziamone soltanto le funzionalit previste.
Essenzialmente le opzioni sono classificabili in 3 categorie:
1) Opzione di vegistvazione del pevcovso.
Quando il trasmettitore setta lopzione di registrazione del percorso,
indica il numero massimo di hop che vuole memorizzare e crea spazio
sufficiente nel campo opzioni per memorizzare tali hop, 32 bit per ogni
indirizzo IP da memorizzare.
Quando il pacchetto IP viaggia per la rete, ogni router toccato dal
datagram IP aggiunge il proprio indirizzo IP alla lista di registrazione
del percorso, almeno fino a che tale lista non piena, nel qual caso il
router si limita ad inoltrare il messaggio.
Quando il pacchetto IP giunge alla destinazione finale, il protocollo IP,
se vuole, pu estrarre la lista dei router toccati dal pacchetto.
Questa opzione viene utilizzata ad es. per implementare lapplicazione
detta traceroute che visualizza i router toccati da un pacchetto.
2) Opzioni di Instvadamento di Pvovenienza.
Le opzioni di Instradamento di Provenienza, consentono al trasmettitore
di imporre ad un pacchetto IP un certo percorso attraverso la rete, anche
se i router normalmente sceglierebbero un percorso diverso. Ci pu
essere utile per effettuare dei test sulla rete. Naturalmente per imporre
linstradamento necessario conoscere la topologia della rete.
Esistono due modalit per linstradamento di provenienza. la prima,
detta instvadamento di pvovenienza sevevo specifica una sequenza di
salti consecutivi, e causa errore se due router non sono consecutivi nella
rete, cio non stanno sulla stessa rete fisica o se il router non pu seguire
quel percorso. La seconda detta instvadamento di pvovenienza
pevmissivo specifica una sequenza di indirizzi IP, ma consente
di attraversare pi reti tra due indirizzi consecutivi.
53
HEADER IPv4 (5)
3) Opzione di contvassegno tempovale.
E simile allopzione di registrazione del percorso, ma aggiunge
allindirizzo IP di ogni router attraversato anche la data e lora in cui il
router gestisce il datagram IP, espresso secondo lora del meridiano di
Greenwich.
Elabovazione delle Opzioni duvante la fvammentazione.
Ciascuna Opzione IP, viene identificata mediante un byte nel campo
Opzioni. Il primo bit (detto bit COPIA) di questo byte stabilisce, quando
posto ad 1, che lopzione deve essere copiata in tutti gli eventuali
frammenti del pacchetto IP. In caso contrario lopzione verr copiata
solo in uno dei frammenti.
Questo diverso comportamento viene configurato in modo diverso per
le diverse Opzioni IP.
Per lopzione di registrazione del percorso, si vuole che lopzione sia
copiata in uno solo dei frammenti, perch essendo ogni frammento
gestito separatamente, potrebbe seguire percorsi diversi verso la
destinazione. Si avrebbero cos pi liste di registrazione del percorso
potenzialmente diverse. Il flag COPIA viene perci posto a zero, e
lopzione copiata in uno solo dei frammenti.
Al contrario, per lopzione di instradamento di provenienza si vuole
che tutti i frammenti seguano lo stesso percorso, e quindi il flag COPIA
viene posto ad uno.
54
HEADER IPv4 (6)
U
n
d
a
t
a
g
r
a
m
d
i

3
7
6
0

b
y
t
e
,

i
n
v
i
a
t
o

d
a

S
=
1
3
0
.
1
3
6
.
2
.
2
0
4

a

D
=
1
3
7
.
2
0
4
.
7
2
.
4
9

,

t
u
t
t
i

i

t
r
a
t
t
i

d
i


r
e
t
e

h
a
n
n
o
M
T
U

d
i

1
5
0
0

b
y
t
e
,

t
r
a
n
n
e

u
n
o

c
h
e

h
a

M
T
U

p
a
r
i

a
5
0
0

b
y
t
e
4
9
b
E
s
e
m
p
i
o
d
i
F
r
a
m
m
e
n
t
a
z
i
o
n
e
M
T
U
1
5
0
0
M
T
U
1
5
0
0
M
T
U
1
5
0
0
M
T
U
5
0
0
4
5
8
2
0
9
9
9
3
7
0
2
5
5
1
7
U
D
P
c
h
s
u
m
3
1
3
0
.
1
3
6
.
2
.
2
0
4
1
3
7
.
2
0
4
.
7
2
.
4
9
0
D
A
T
I
:


2
9
6
0
-
3
7
5
9
M
T
U
1
5
0
0
4
5
1
5
0
0
9
9
9
0
2
5
5
U
D
P
c
h
s
u
m
1
1
3
0
.
1
3
6
.
2
.
2
0
4
1
3
7
.
2
0
4
.
7
2
.
4
9
1
D
A
T
I
:







0
-
1
4
7
9
1
5
0
0
9
9
9
1
8
5
2
5
5
U
D
P
c
h
s
u
m
2
1
3
0
.
1
3
6
.
2
.
2
0
4
1
3
7
.
2
0
4
.
7
2
.
4
9
1
D
A
T
I
:




1
4
8
0
-
2
9
5
9
M
T
U
1
5
0
0
4
5
5
0
0
9
9
9
3
7
0
2
5
4
1
7
c
h
s
u
m
4
1
3
0
.
1
3
6
.
2
.
2
0
4
1
3
7
.
2
0
4
.
7
2
.
4
9
1
D
A
T
I
:





2
9
6
0
-
3
4
3
9
4
5
3
4
0
9
9
9
4
3
0
2
5
4
1
7
c
h
s
u
m
5
1
3
0
.
1
3
6
.
2
.
2
0
4
1
3
7
.
2
0
4
.
7
2
.
4
9
0
D
A
T
I
:







3
4
4
0
-
3
7
5
9
S
1
3
0
.
1
3
6
.
2
.
2
0
4
D
1
3
7
.
2
0
4
.
7
2
.
4
9
p
a
c
c
h
e
t
t
i

i
n
v
a
r
i
a
t
i
,
t
r
a
n
n
e
T
T
L
d
e
c
r
e
m
e
n
t
a
t
o
f
r
a
m
m
e
n
t
a
z
i
o
n
e
i
n
i
z
i
a
l
e
f
r
a
m
m
e
n
t
a
z
i
o
n
e
d
e
l
f
r
a
m
m
e
n
t
o
r
i
a
s
s
e
m
b
l
a
g
g
i
o
d
e
i

f
r
a
m
m
e
n
t
i
1
4
8
0
1
4
8
0
8
0
0
0
1 4 7 9
1 4 8 0
2 9 5 9
2 9 6 0
3 7 5 9
1
4
8
0
1
4
8
0
3
2
0
4
8
0
0
1 4 7 9
1 4 8 0
2 9 5 9
2 9 6 0
3 7 5 9
3 4 3 9
3 4 4 0
0
x
8
=
0
1
8
5
x
8
=
1
4
8
0
3
7
0
x
8
=
2
9
6
0
4
3
0
x
8
=
3
4
4
0
M
T
U
1
5
0
0
M
T
U
M
T
U
1
5
0
0
0
1
7
c
h
s
u
m
1
c
h
s
u
m
1
4
5
1
7
M
T
U
1
5
0
0
9
9
9
9
9
9
S
1
3
0
.
1
3
6
.
2
.
2
0
4
D
1
3
7
.
2
0
4
.
7
2
.
4
9
p
a
c
c
h
e
t
t
i

i
n
v
a
r
i
a
t
i
,
t
r
a
n
n
e
T
T
L
d
e
c
r
e
m
e
n
t
a
t
o
f
r
a
m
m
e
n
t
a
z
i
o
n
e
i
n
i
z
i
a
l
e
f
r
a
m
m
e
n
t
a
z
i
o
n
e
d
e
l
f
r
a
m
m
e
n
t
o
r
i
a
s
s
e
m
b
l
a
g
g
i
o
d
e
i

f
r
a
m
m
e
n
t
i
1
4
8
0
1
4
8
0
8
0
0
0
1 4 7 9
1 4 8 0
2 9 5 9
2 9 6 0
3 7 5 9
0
1 4 7 9
1 4 8 0
2 9 5 9
2 9 6 0
3 7 5 9
3 4 3 9
3 4 4 0
0
x
8
=
0
1
8
5
x
8
=
1
4
8
0
3
7
0
x
8
=
2
9
6
0
4
3
0
x
8
=
3
4
4
0
Larchitettura TCP/IP (il cui nome pi preciso Intevnet Pvotocol
Suite) formata da diversi componenti, che si posizionano nello
stack dei protocolli a partire dal livello 3 (network).
I protocolli appartenenti a questa architettura sono specificati
tramite standard denominati RFC (Request For Comments)
disponibili in rete. Ad es. lRFC 791 specifica il protocollo IP.
Il protocollo IP (Intevnet Pvotocol) il protocollo principale del
livello 3 dellarchitettura TCP/IP. Si tratta di un protocollo
semplice, di tipo datagram ovvero senza connessione e non
affidabile;
non affidabile: il pacchetto inviato pu essere perso, duplicato
ritardato o consegnato fuori sequenza, ma il protocollo IP non
informer n il trasmettitore n il ricevitore.
senza connessione: ogni pacchetto viene trattato in maniera
indipendente dagli altri, pacchetti diversi aventi stesso mittente e
stesso destinatario possono seguire percorsi diversi, alcuni possono
essere consegnati ed altri no. Se le risorse della rete lo consentono
il pacchetto viene portato a destinazione, in caso contrario
verr scartato.
Il livello Network del TCP/IP.
Il protocollo IP (versione 4)
42
Attualmente lo standard per il livello network dello stack TCP/IP
rappresentato dal protocollo IP versione 4, ma gi dal 1995 stata
proposta una nuova versione del protocollo IP, nota col nome di IP
versione 6 (RFC 1883: Internet Protocol, Version 6 (IPv6)
Specification, December 1995 R. Hinden, S. Deering ).
IP versione 4 versione soffre di almeno 3 problemi principali, che
IPv6 vuole correggere:
numevo degli indivizzi IP disponibili ovmai insufficiente: gli
indirizzi IP sono composti da 4 byte (32 bit) e a causa del grande
incremento del numero degli hosts nel mondo la disponibilit degli
indirizzi in forte calo. Il protocollo IPv6 prevede invece indirizzi
formati da 16 byte (128 bit) e quindi rende disponibili un numero
enorme di indirizzi.
tvaffico gestito esclusivamente in modo best-effovt: in IPv4 tutti i
pacchetti sono trattati allo stesso modo dai router, anche se esiste
nellheader dei pacchetti IPv4 un campo priorit, che per non viene
utilizzato. Con IPv6 si vuole definire delle classi di servizio a cui
assegnare priorit diverse. Si vuole anche gestire la comunicazione
con un meccanismo simile ad un protocollo con connessione, cio
implementando un flusso di dati.
sicuvezza: in IPv6 saranno rese standard e disponibili alcune
primitive per lautenticazione e la cifratura dei dati.
Nonostante queste prospettive, il protocollo IP versione 6 ancora
poco diffuso, e rimane ancora a livello di sperimentazione, forse
perch ladozione del nuovo protocollo costringerebbe a modificare
fortemente gli apparati di rete esistenti, con un grande dispendio di
denaro. Esistono a tuttoggi, in un oceano IPv4, solo delle isole in cui
si parla IPv6.
Nel seguito parleremo di IPv4, che rappresenta ancora lo
standard pi diffuso.
Il protocollo IP versione 6
43
Il protocollo IP svolge le seguenti funzioni:
distingue ogni hosts, o meglio ogni scheda di vete mediante un
identificatove, detto indivizzo IP. Un indirizzo IP di tipo single o
unicast identifica un unico host, ma uno stesso host pu avere pi
indirizzi IP unicast, tanti quante sono le schede di rete che
possiede. Si parla allora di MultiHomed Systems. Ad es. i router
hanno pi indirizzi, perch dovendo fungere da centri di
smistamento dispongono di pi schede di rete. Un host pu
comunque disporre di pi schede di rete anche senza essere un
router, cio anche se non effettua un servizio di instradamento per
pacchetti destinati ad altri hosts, ma dovr prevedere una politica
che definisca quale scheda di rete utilizzare per inviare i dati.
viceve i dati (una sequenza di PDU) dal livello tvaspovto (4).
incapsula ciascuna PDU vicevuta in pacchetti di dimensione
massima 64 Kbyte (normalmente circa 1500 byte), aggiungendovi
un pvopvio headev (o intestazione).
eventualmente fvammenta i pacchetti allinizio o durante il
trasporto, per inserirli nei frame di livello 2.
instvada i pacchetti sulla rete,
effettua la vilevazione, non la correzione, degli evvovi,
alla destinazione, se necessario, viassembla i fvammenti
ricostruendo i pacchetti originali,
estvae dai pacchetti i dati (PDU) del livello tvaspovto,
consegna al livello tvaspovto i dati nell`ovdine in cui sono
avvivati a destinazione, che pu essere diverso dallordine
in cui sono partiti.
Funzioni del protocollo IPv4
44
header del
Datagram IP
area dati del Datagram IP
(PDU del livello trasporto)
Un pacchetto IP costituito da un header e da una parte dati, che
rappresenta la porzione di dati del livello trasporto da trasferire.
Lheader IP ha:
una prima parte fissa di 20 bye,
una seconda parte, opzionale, di lunghezza variabile, ma sempre
multiplo di 4 byte
ed strutturato come segue.
byte 0-3
byte 4-7
byte 8-11
byte 12-15
byte 16-19
byte .....
Il campo Vevsion (di 4 bit) indica la versione del protocollo IP
che ha generato il pacchetto. Serve al ricevente per capire il
formato del pacchetto che st ricevendo. Se lo standard cambia, ad
es. il passaggio da IPv4 (Version=4) ad IPv6 (version=6) il
ricevente capisce da questo campo come deve trattare il pacchetto.
Il campo HLEN (anchesso di 4 bit) indica la lunghezza
dellHeader IP misurata in wovd di 4 byte. Se HLEN vale 7
lheader lungo 4*7=28 byte. Tutti i campi dellheader hanno
lunghezza fissa, tranne il campo Options, di lunghezza variabile,
ed il corrispondente campo PAD (Riempimento) che serve a
rendere lheader lungo un multiplo di 4 byte.
Il pacchetto IPv4: lo HEADER
45
header del
Datagram IP
area dati del Datagram IP
(PDU del livello trasporto)
D
F
M
F
Version HLEN Type of service Total length
Identification Fragment offset
Time to live Protocol Header checksum
Source IP address
Destination IP address
32 bit
4 4 8 1 1 1
Pad (Riempimento)
Options
Il campo Total Length (di 16 bit) indica la lunghezza totale del
pacchetto IP, espvessa in byte, e comprende sia lheader che il campo
dati. Quindi se Total Length = 50 il pacchetto IP lungo 50 byte.
Poich il campo lungo 16 bit la massima lunghezza possibile per un
pacchetto IP di 2
16
-1=65535 byte.
Il campo Type of Sevvice (di 8 bit) rappresenta unindicazione ai
voutev sulla qualit del tvaspovto che possibilmente il pacchetto IP
dovvebbe spevimentave. Il router dovrebbe basarsi anche su queste
indicazioni per decidere la precedenza dei pacchetti nelle sue code, e
linstradamento. Ad es. se il pacchetto richiede un certo ritardo
massimo, il router potrebbe decidere di instradarlo su un percorso
attraverso una rete ATM a cui chiedere garanzie sul ritardo massimo
piuttosto che attraverso una rete con servizio di tipo Best Effort che
non pu offrire garanzie.
I primi 3 bit definiscono un campo Pvecedenza con valori da 0 a
7, al crescere del quale cresce limportanza del pacchetto IP. Il
valore 0 indica precedenza normale, il valore 7 un pacchetto di
controllo della rete, e quindi maggiore importanza.
I bit 3 (D=Delay), 4 (T=Throughput) e 5 (R=Reliability) indicano
il tipo di trasporto preferito: D settato (D=1) indica richiesta di
basso ritardo, T settato chiede un elevato throughtput (ampia banda
di trasmissione), R settato indica richiesta di massima affidabilit.
I bit 6 e 7 non sono usati.
Di solito per i router non tengono conto delle preferenze espresse
mediante il campo Type of Service. Attualmente si studiano delle
politiche (note come Diffeventiated Sevvices) che cercano di
realizzare routing e buffering basandosi sulla classificazione
delle applicazioni proprio in base a indicazioni di questo tipo.
HEADER IPv4 (2)
46
Precedenza Non Usati R T D
0 1 2 3 4 5 6 7
Lhardware di ogni tipo di rete impone un limite superiore alla
dimensione del frame di livello 2, e quindi anche alla quantit di dati
di livello 3 che possono essere trasportati in un unico frame a livello 2.
La dimensione massima di dati di livello 3 che possono essere
trasportati in un frame del Data Link viene chiamata Massima Unit
di Tvasfevimento (MTU: Maximum Tvansfev Unit), ed
caratteristico di ogni tipologia di rete. Per Ethernet MTU=1500 bytes.
Se la porzione dati di un datagram IP (pi la dimensione dellheader
IP) pi piccola della MTU della rete sottostante, il datagram IP potr
essere inserito completamente in un frame di livello 2 e inviato a
destinazione.
Se invece la porzione dati del datagram IP ( pi la dimensione
dellheader IP) pi grande della MTU della rete sottostante, la
povzione dati dovr essere spezzata in pi pezzi che verranno
incapsulati in datagram IP (detti frammenti) pi piccoli della MTU, e
ciascun frammento dovr essere inserito in un frame diverso e verr
spedito separatamente dagli altri verso la destinazione finale, dove il
protocollo IP provveder a rimettere assieme i diversi frammenti e a
ricostituire il datagram originale. Nellesempio un pacchetto IP con
3260 byte di dati frammentato per una MTU di 1500 byte.
47
La Frammentazione dei pacchetti IP
frammento 1 (offset 0) (MF=1)
frammento 1 (offset 1480)( MF=1)
frammento 3 (offset 2960) (MF=0)
Header Frame Area Dati Frame
Header Datagram IP Area Dati Datagram IP
header frammento 1
(20 byte)
Dati 1
(1480 byte)
header datagram IP
(20 byte)
Dati 1
(1480 byte)
Dati 2
(1480 byte)
Dati 3
(300 byte)
header frammento 3
(20 byte)
Dati 3
(300 byte)
header frammento 2
(20 byte)
Dati 2
(1480 byte)
il problema della frammentazione si propone ogni volta che nel
percorso seguito dai pacchetti IP, si deve attraversare una porzione di
rete avente una MTU minore della porzione di rete precedentemente
attraversata, sempre se la dimensione dei pacchetti IP maggiore della
MTU pi piccola.
Il router preleva allora la porzione dati del datagram IP e lo spezza in
pi porzioni, in modo che ciascuna (aggiungendovi lheader) stia in un
frame, e in modo che ogni frammento dei dati, tranne lultimo, abbia
dimensione multipla di 8 byte, perch cos definito il campo offset
dellheader IP.
Lultimo pezzo in genere sar il pi corto e verr identificato come
ultimo settandovi a zero il flag MoveFvagment, ad indicare che
lultimo frammento. Negli altri frammenti MF settato a 1.
Il protocollo IP usa tre campi dellheader per controllare il
meccanismo della frammentazione e permettere il riassemblaggio dei
datagram frammentati. Questi campi sono Identification (16 bit),
Fvagment Offset (15 bit) e il flag Move Fvagment (MF).
48
La Frammentazione dei pacchetti IP
D
F
Version HLEN Type of service Total length
Time to live Protocol Header checksum
Source IP address
Destination IP address
32 bit
4 4 8 1 1 1
Pad (Riempimento)
Options
M
F
Fragment offset Identification
L`headev del datagvam oviginale vevv copiato integvalmente nei
fvammenti (con qualche modifica per il campo Options) e in pi verr
cambiato il campo Fvagment Offset che indica il punto dell`avea
dati del datagvam oviginale in cui comincia la povzione di dati
tvaspovtata nel fvammento. Tale offset pensato come un multiplo
di 8 byte. Se loffset indica ad es. 185, il frammento porta la porzione
di dati che inizia nella posizione 185*8=1480 byte.
Tutti i fvammenti sono caratterizzati dallavere lo stesso
identificatore (il campo Identification) del datagram originale. Tale
numero assegnato univocamente dal trasmettitore (che mantiene un
contatore dei datagram IP trasmessi), e la coppia (IP Provenienza,
Identification) rende univocamente identificabile un certo
datagram IP, e tutti i suoi frammenti.
49
La Frammentazione dei pacchetti IP
Dopo la frammentazione, ogni frammento viaggia separatamente dagli
altri fino alla destinazione finale. Solo alla fine del viaggio avr luogo
il riassemblaggio dei frammenti, nel tentativo di ricostruire il
datagram Originale.
Il ricevitore riconosce di avere ricevuto un frammento e non un
datagram intero in due modi:
il pacchetto IP ricevuto ha un offset uguale a zevo, ma ha il flag
Move Fvagment settato ad uno ( il primo frammento).
il pacchetto IP ricevuto ha un offset divevso da zevo ( un
frammento successivo). Se il More Fragment zero lultimo
frammento.
Il protocollo IP del ricevente identifica univocamente i frammenti di
uno stesso datagram mediante la coppia (IP tvasmettitove,
Identification del datagvam).
Il ricevente non conosce la dimensione del datagram originale perch
ogni frammento mantiene nel campo Total Length la lunghezza del
frammento stesso, e non quella del datagram originale. Solo quando
ricever il frammento con il flag Move Fvagment settato a zevo(che
indica lultimo frammento del datagram originale), si potr capire la
dimensione totale del datagram originale sommando alloffset
dellultimo frammento la lunghezza dei dati trasportati nellultimo
frammento.
Se un solo frammento viene perso, impossibile ricostruire il
datagram IP originale.
Per evitare di aspettare inutilmente un frammento perso, il ricevitore
nel momento in cui riceve un primo frammento inizializza un timer.
Se il timer scade prima che tutti i frammenti siano giunti a
destinazione il ricevitore butta via tutti i frammenti.
50
Il Riassemblaggio dei Frammenti
Il campo Time To Live (TTL, tempo di vita, di 8 bit) indica in modo
approssimato il tempo, in secondi, che un pacchetto IP pu rimanere
allinterno di una rete prima di essere scartato.
-Tale valore viene inizializzato a 255 dallhost che spedisce il
pacchetto IP. Ogni volta che un router processa quel pacchetto IP,
decrementa di una unit questo contatore. Quando il contatore
raggiunge il valore zero, il router scarta il pacchetto.
-Per ovviare al problema della congestione della rete che causa lunghe
attee in coda, quando il router riceve un pacchetto e lo mette in coda in
attesa per spedirlo, salva il valore corrente dellorologio.
-Quando il pacchetto deve essere spedito si calcola il tempo (in
secondi) trascorso in coda e si decrementa di questo tempo il
contatore TTL.
-Grazie al contatore TTL, i pacchetti IP non possono viaggiare in
eterno nella rete anche se per un errore i router li instradano in un
percorso ciclico, e si evitano cos congestioni nella rete.
-Quando un pacchetto IP viene frammentato durante il percorso, tutti i
suoi frammenti vengono incapsulati con il TTL residuo del pacchetto.
Il campo Pvotocol (di 8 bit) indica di quale tipo il dato trasportato
nellarea dati del pacchetto IP, ovvero indica qual il protocollo di
livello 4 (o 3) che ha generato i dati trasportati dal pacchetto IP. In tal
modo il livello Network sa a quale protocollo dovr consegnare i dati
trasportati. Tra i protocolli che possono essere trasportati nellarea dati
ricordiamo:
0 ICMP Internet Control Message Protocol
4 IP IP in IP (incapsulamento, tunneling)
6 TCP Transmission Control Protocol
17 UDP User Datagram Protocol
29 ISO-TP4 ISO Transport Protocol Class 4
93 AX.25 AX.25 frames
51
HEADER IPv4 (continua 3)
Il campo Headev Checksum (di 16 bit) serve a verificare che lo
headev IP sia avvivato integvo a destinazione. Viene codificato
utilizzando i byte del solo header. Se durante il trasporto lheader
subisce delle modifiche, la checksum risulta diversa e il protocollo IP
capisce che c stato un errore.
Notare che la checksum verifica lintegrit del solo header, e non dei
dati trasportati.
Il vantaggio di aveve una checksum sepavata pev headev e dati
che:
i protocolli di livello superiore possono scegliere una loro codifica
per il controllo degli errori,
i router diminuiscono il tempo necessario a calcolare la checksum,
perch devono processare solo lheader, che di solito pi piccolo
dei dati trasportati.
Di contro, lo svantaggio di avere a livello IP una checksum solo per
lheader IP impedisce al livello 3 di accorgersi di eventuali errori sui
dati di livello 4, fino a che tali dati non sono giunti a destinazione
finale, e solo allora il protocollo di livello 4 effettuer il controllo sui
dati con delle proprie checksum. Per il livello 2 potrebbe avere gi
riconosciuto un errore e scartato il frame.
I campi Souvce IP addvess e Destination IP addvess contengono
gli indirizzi IPv4 a 32 bit della provenienza originale e della
destinazione finale del datagramma IP. Tali indirizzi quindi non
cambiano mai durante tutto il percorso, comunque venga instradato il
pacchetto, e comunque venga frammentato.
Il campo Options, di lunghezza variabile, e poich lheader IP
deve avere lunghezza pari ad un multiplo di 4 byte, viene introdotto
ove necessario un ultimo campo Padding di riempimento,
per arrivare alla giusta lunghezza.
52
HEADER IPv4 (4)
Gli indirizzi IP, che devono essere univoci sulla rete, sono lunghi 32
bit (quattro byte) e sono tradizionalmente visualizzati scrivendo i
valori decimali di ciascun byte separati dal carattere punto.
Gli indirizzi IP comprendono due o tre parti. La prima parte indica
l'indirizzo della rete (network), la seconda (se presente) quello della
sottorete (subnet) e la terza quello dell'host.
Si noti che non sono gli hosts ad avere un indirizzo IP, bens le
interfacce di rete. Quindi se un nodo ha tre interfacce, esso ha tre
indirizzi IP. Poich la maggior parte degli hosts ha una sola
interfaccia di rete, parlando di indirizzo IP di un host si fa
riferimento allindirizzo della sola interfaccia di rete presente.
Gli indirizzi IP sono suddivisi in cinque classi, di cui le prime 3,
denominate A, B e C, servono ad individuare singole interfacce di
rete e differiscono per il numero di host che ciascuna rete pu
indirizzare, mentre le altre due classi D ed E sono utilizzate per
servizi assai differenti. Ad es. le reti dellUniversit di Bologna
(130.136.*.* , 137.204.*.* ) sono di classe B.
- Classe A. Sono concepiti per poche reti di dimensioni molto
grandi. Gli indirizzi di classe A sono riconoscibili in quanto il il bit
pi significativo del primo byte posto a zero, e quindi il primo
campo dell'indirizzo compreso tra 0 e 127. I bit che indicano la rete
sono 7 e quelli che indicano l'host 24. Quindi si possono avere al
massimo 128 reti di classe A, ciascuna con una dimensione massima
di circa 16 milioni di indirizzi.
55
INDIRIZZAMENTO IP
- Classe B. Sono pensati per un numero medio reti di dimensioni
medio-grandi. Gli indirizzi di classe B si riconosconno perch i 2
bit pi significativi del primo byte sono posti a 10, quindi il primo
campo dell'indirizzo compreso tra 128 e 191. I bit che indicano la
rete sono 14 e quelli che indicano l'host 16. Si possono avere circa
16000 reti di classe B, ciascuna con circa 64000 indirizzi.
- Classe C. Sono concepiti per identificare molte reti di dimensioni
piccole. Gli indirizzi di classe C hanno i primi 3 bit settati a 110 e
quindi il primo campo dell'indirizzo compreso tra 192 e 223. I bit
che indicano la rete sono 21 e quelli che indicano l'host 8. Quindi si
possono avere al massimo 2 milioni di reti di classe C, ciascuna con
una dimensione massima di 256 indirizzi.
- Classe D. Sono indirizzi usati per applicazioni di multicast . Gli
indirizzi di classe D si riconoscono perch i primi 4 bit del primo
byte sono settati a 1110, e quindi il primo campo dell'indirizzo
compreso tra 224 e 239.
- Classe E. Questi indirizzi sono riservati per usi futuri. Gli
indirizzi di classe E hanno i 4 bit pi significativi settati a 1111, e
quindi il primo campo dell'indirizzo compreso tra 240 e 255.
56
INDIRIZZAMENTO IP (2)
127 qualunque numero
0 1 2 7 8 31
loopback
Esistono inoltre indirizzi IP con significato particolare, ad esempio
per gli indirizzi di broadcast e per il loopback.
57
INDIRIZZAMENTO IP (3)
tutti 0
0 1 2 7 8 31
questo host
tutti 1
0 1 2 7 8 31
broadcast su
questa network
(non ammesso come indi_
rizzo di provenienza)
(suggerimento: provare su s.o. Linux il comando ping 0.0.0.0)
(suggerimento: provare il comando ping 255.255.255.255)
lhost specificato
in questa rete
(non ammesso come indi_
rizzo di destinazione)
(serve solo allavviamento)
tutti 0 host
0 1 2 15 16 31
(suggerimento: provare il comando ping 0.0.0.204)
rete tutti 1
0 1 2 15 16 31
Broadcast per la
rete specificata
(non ammesso come indi_
rizzo di provenienza)
(suggerimento:staccare il cavo di rete e provare il comando ping 127.5.6.7)
Quando si utilizza il loopback, il pacchetto non viene inviato sulla
rete ma viene passato ai moduli IP di ricezione, ed elaborato come
se fosse in arrivo: ci serve ad es. per effettuare localmente
dei test su un software di rete in fase di sviluppo.
E necessario creare un insieme di protocolli di rete che non
dipendano dallarchitettura del computer o della scheda di rete. Non
tutte le architetture di calcolatori memorizzano i dati nello stesso
modo. In particolare gli interi di 32 bit (le dimensioni dellindirizzo
IP) sono memorizzati in due modi diversi: le macchine Little Endian
mantengono il byte meno significativo nellindirizzo di memoria pi
basso, le macchine Big Endian mantengono il byte pi significativo
nellindirizzo di memoria pi basso.
Per evitare confusione, ovvero per evitare che un indirizzo IP
possa venire scritto in due modi diversi, i protocolli TCP/IP
definiscono un ordine di byte standard della rete, che tutte le
macchine devono usare per i campi dei protocolli IP, ovviamente
non per la parte dati.
In trasmissione, prima di scrivere ad es. unindirizzo IP nel campo
destinazione del pacchetto IP, lhost deve convertire il numero IP
dalla sua propria rappresentazione alla rappresentazione standard
per la rete.
In ricezione, prima di valutare lindirizzo IP contenuto nel campo
provenienza del pacchetto IP, deve convertire tale campo dal
formato di rete standard nel formato interno della macchina.
Internet stabilisce come ordine standard per gli interi a 32 bit,
quello che prevede che i byte pi significativi siano trasmessi per
primi (stile Big Endian). Guardando viaggiare i dati da una
macchina allaltra, un intero a 32 bit comincia ad essere trasmesso
dal byte pi significativo, cio col byte pi significativo pi vicino
allinizio del pacchetto. Le librerie socket forniscono per le
conversioni delle funzioni
che sono: ntohs,ntohl,
htons,htonl.
58
LORDINE dei BYTE in RETE
byte 3 byte 2 byte 1 byte 0
byte
address
Big Endian
byte 3 byte 2 byte 1 byte 0
fine
pacchetto
inizio
pacchetto
direzione di trasmissione
Il routing IP, ovvero linstradamento di un pacchetto IP verso la
destinazione specificata nellheader del pacchetto IP viene
effettuato secondo le seguenti modalit:
Un certo host deve inviare un pacchetto IP verso una destinazione
IP_D (oppure un router ha ricevuto un pacchetto e deve instradarlo
verso la destinazione IP_D).
lhost controlla lindirizzo IP di destinazione per capire se
lindirizzo IP_D appartiene alla sua stessa sottorete cio se la
destinazione raggiungibile in modo diretto mediante il MAC
address cio sfruttando il solo livello 2, ovvero se per raggiungere la
destinazione non necessario attraversare router (livello 3) ma al
massimo si attraversano dei bridge (vedi subnetting).
Se la destinazione sta sulla stessa sottorete dellhost, si usa la
consegna diretta, cio lhost trova (col protocollo ARP) lindirizzo
di livello 2 di destinazione (MAC_D), incapsula il pacchetto IP in
un pacchetto di livello 2 con quellindirizzo MAC_D come
destinazione, e lo invia in rete.
La destinazione MAC_D a livello 2 vede passare il pacchetto,
vede il proprio indirizzo MAC_D e carica il pacchetto passandolo al
livello IP ed il gioco fatto.
Se invece la destinazione non sta sulla stessa sottorete si usa la
consegna indiretta, cio lhost deve inviare il pacchetto IP al router
di default, ovvero un router che lhost conosce e che sta sulla stessa
sottorete dellhost. Lhost cerca (ancora con il protocollo ARP)
lindirizzo di livello 2 del default router (MAC_R), incapsula il
pacchetto IP in un pacchetto di livello 2 con quellindirizzo MAC_R
come destinazione, e lo invia in rete.
Il router vede passare il pacchetto con il proprio MAC address, lo
carica, estrae il pacchetto IP, vede che lindirizzo IP_D non
il suo e lo instrada con lo stesso meccanismo gi visto.
59
Approccio al ROUTING IP (1)
60
Approccio al ROUTING IP (2)
S
cagnina
130.136.3.204
D
sangiovese
130.136.3.203
bridge (quindi livello 2), invisibile al livello IP,
instrada i pacchetti tramite il MAC address
S
cagnina
130.136.3.204
D
sangiovese
130.136.3.203
BRIDGE
Consegna Diretta (via MAC address)
Sorgente S e destinazione D appartengono alla stessa sottorete
anche se in mezzo ce un bridge, perch lavorando a livello 2
instrada i pacchetti mediante i MAC address, e non gli indirizzi IP
Consegna Indiretta (via IP address)
Sorgente S e destinazione D non stanno sulla stessa sottorete
in mezzo ce un router, che lavora a livello 3,
necessario routing a livello IP
sarastro.cs.unibo.it
130.136.2.10
S
cagnina
130.136.3.8
D
ROUTER
130.136.3.252 130.136.2.253
MAC_S MAC_R3 MAC_R2
MAC_D
Un certo indirizzo di rete di classe A, B o C permette di mappare
un certo numero di hosts, come appartenenti ad una stessa rete.
Per una rete fisica, a seconda della sua topologia, della
disposizione degli apparati di routing e bridging, e di criteri di
opportunit vari, pu essere intrinsecamente costituita da pi parti,
connesse in varia maniera, ciascuna delle quali costituisce una rete
broadcast a livello 2.
Si cercato di indirizzare ciascuna di queste porzioni di rete in
modo separato, senza essere costretti ad utilizzare per ciascuna di
esse una diversa rete (non sono poi cos tante le reti disponibili).
Il meccanismo del subneting serve proprio a descrivere la
situazione in cui alcuni host sono in grado di comunicare tra loro in
modo diretto via livello 2, in modo da dar loro la possibilit di
scambiarsi direttamente i pacchetti IP senza utilizzare un router, e si
dice allora che gli host appartengono alla stessa sottorete.
Il meccanismo consiste nel considerare la parte host delindirizzo
IP di un host, come formato da due parti, la subnet e lhost. A
seconda dellampiezza del campo dedicato alla subnet, si possono
ottenere molte subnet contenenti ciascuna pochi host, o poche
subnet contenenti molti hosts.
Lampiezza dei campi subnet e host viene definita mediante un
parametro, detto netmask, configurato uguale per tutti gli host della
stessa subnet. La netmask contiene i bit ad uno in corrispondenza
dei campi network e subnet dellindirizzo IP, e a zero in
corrispondenza del campo host.
Ad es. una netmask 11111111111111111111111100000000, pi
comunemente scritta come indirizzo IP 255.255.255.0 (o in
esadecimale ffffff00), indica che il campo host coincide con
lultimo byte dellindirizzo IP
61
SUBNET IP (1)
Con il subnetting dellesempio qui sopra, a partire da uno stesso
indirizzo di classe B, otteniamo 256 diverse sottoreti, ciascuna con
254 indirizzi disponibili per gli host (256 -broadcast(1) -questo(0)).
Algoritmo di Riconoscimento di Appartenenza a stessa subnet.
Dato un indirizzo IP di un host, e la netmask per la sua sottorete,
dato un altro indirizzo IP (ad. es. di un host a cui il primo deve
spedire un pacchetto) per capire se i due indirizzi appartengono alla
stessa sottorete, ogni indirizzo viene messo in AND bit a bit con la
netmask, ottenendo due valori che sono la parte network e subnet
dei due indirizzi. Se questi due valori sono uguali, allora i due
indirizzi IP stanno sulla stessa sottorete, altrimenti stanno su
sottoreti diverse.
Ad es., una rete (classe B) 130.136.*.* con netmask 255.255.255.0,
i due indirizzi 130.136.3.204 e 130.136.3.203 stanno sulla stessa
sotorete, perch dallAND bit a bit di indirizzi e netmask si
ottiene 130.136.3.0, quindi i due IP sono nella stessa subnet.
62
SUBNET IP (2)
Vediamo un esempio di indirizzo di una classe B, a cui viene
applicata una netmask 255.255.255.0 , in modo che la parte host
viene partizionata in una parte subnet ed una host di 8 bit ciascuna.
1 0
0 1 2 7 8 15 16 23 24 31
network host
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 1 2 7 8 15 16 23 24 31
netmask
1 0
0 1 2 7 8 15 16 23 24 31
network subnet host
indirizzo di
classe B
netmask
subnetting
Come abbiamo visto poco fa (slide 59) limportanza di capire se due
host stanno sulla stessa sottorete risiede nel fatto che in IP il routing
minimo (consegna diretta) realizzabile solo se i due hosts stanno
sulla stessa sottorete.
Quindi, in tecnologia IP una subnet deve coincidere con una rete
fisica (*), o meglio deve coincidere con linsieme degli host che
possono comunicare tra loro via broadcast di livello2 , e quindi pu
coincidere anche con un insieme di pi reti fisiche connesse
mediante bridges (livello 2).
(*) In realt, il concetto di subnet stato rilassato, e si permette che:
una stessa rete fisica (una LAN) (o pi reti fisiche interconnesse
da bridge) possa contenere pi subnet IP, qualora sia necessario
partizionare una rete fisica in modo logico.
Invece una subnet IP non pu mai contenere pi reti fisiche
interconnesse da router, cio una subnet IP non pu mai attraversare
dei router. (**)
(**) Anche questa affermazione messa in forse dallavvento di
concetti quali le LAN virtuali, che per non chiaro a quale livello
debbano essere collocate. Quindi per ora ci teniamo il concetto di
subnet IP come rete capace di comunicare per mezzo del
broadcast di livello 2.
63
SUBNET IP (3)
Bridge
Router
130.136.3.0
130.136.2.0
130.136.2.0
cagnina
130.136.3.204
130.136.3.251
130.136.2.253
sangio
vese
130.136.3.203
timur
130.136.2.7
sarastro
130.136.2.10
Per come viene effettuato il routing in IP, le informazioni che un
host deve conoscere per poter instradare correttamente i pacchetti
che vuole spedire sono:
il proprio indirizzo MAC, che legge nella sua scheda di rete,
il proprio indirizzo IP, che pu essere assegnato e salvato su file
o gli pu essere assegnato al boot (per i sistemi diskless, mediante il
protocollo RARP a partire dal MAC address),
lindirizzo IP di un router di default, a cui consegnare tutti i
pacchetti IP per indirizzi che non stanno nella sua stessa sottorete,
un criterio per sapere quali hosts stanno nella sua sottorete, in
modo da poter decidere se spedire i pacchetti direttamente (previa
richiesta ARP) o se instradarli via default router. Tale criterio
costituito dalla cosiddetta netmask, che lamministratore di rete
assegna ad ogni host, la stessa per tutti gli hosts della sottorete.
La sottorete a cui un host (un IP address) appartiene costituita da
quegli host che:
1) appartengono alla stessa rete IP, cio hanno stesso indirizzo di
rete (sia essa di classe A B o C),
2) appartengono alla stessa rete fisica (o a reti fisiche diverse ma
separate solo da bridge, che inoltrano via MAC address) e
quindi propagano i broadcast di livello 2, per permettere ad es. di
comunicare tramite livello 2 direttamente e di effettuare la chiamata
al protocollo ARP,
3) hanno avuto assegnata la stessa netmask, che individua
lappartenenza ad una stessa sottorete,
4) hanno indirizzo IP e netmask tali che lAND bit a bit tra
indirizzo IP e netmask da lo stesso risultato per tutti gli IP
della sottorete (criterio di appartenenza ad una stessa
sottorete).
64
Informazioni per Routing in un Host
--- --- Ogni Ogni host host deve mantenere deve mantenere le le seguenti informazioni seguenti informazioni: :
il proprio indirizzo MAC,
il proprio indirizzo IP,
lindirizzo IP di un router di default nella stessa sottorete,
la netmask della sua sottorete (riconoscere gli IP della sottorete).
--- Un host per inviare un datagramIP,
fa lAND bit a bit della netmask, una volta con lindirizzo di
destinazione, ed una volta con il proprio indirizzo IP.
Se i due risultati sono uguali lindirizzo di destinazione
appartiene alla sua stessa sottorete, e lhost usa linstradamento
diretto, inviando il datagram in un frame di livello 2 avente, come
indirizzo di livello 2, il MAC address della destinazione.
In caso contrario lhost invia il pacchetto IP (che ha nellheader
lindirizzo di destinazione IP) incapsulato in un frame destinato
al router di default cio avente MAC address del router sulla
stessa rete, ed il salto successivo lo decider il router (Next Hop).
Qualunque sia la destinazione a livello 2 (il router per il primo
salto o lhost destinazione in caso di consegna diretta) il MAC
address verr ottenuto con chiamata ARP o alla cache ARP.
La destinazione a livello 2 vede transitare il proprio indirizzo
MAC, carica il frame, toglie lincapsulamento e passa al livello IP.
Nellhost di destinazione, il livello IP riconosce nellindirizzo IP
di destinazione del pacchetto IP il proprio indirizzo IP e consegna il
pacchetto IP al protocollo superiore.
Invece il router si accorge che il pacchetto IP non per lui, e
decide di instradarlo, consulta delle tabelle di instradamento (coppie
(subnet, interface)) e se lIP destinazione del pacchetto sta nella
sottorete di una interfaccia instrada in modo diretto, altrimenti
sceglie (tra i router a lui direttamente collegati) quale usare per
instradare il pacchetto; il prossimo router sceglie il successivo hop.
65
Il Routing in Internet Protocol
Il concetto di subnet introduce quindi un livello di gerarchia nelle
reti TCP/IP. Il routing si scinde in:
un routing allinterno della subnet,
un routing tra subnet diverse ma gestite da una stessa autorit, i
cosiddetti autonomous systems (es. lUniv. di Bologna),
un routing tra diversi autonomous systems.
Il routing allinterno della subnet banale (* in teoria) perch la
subnet coincide con una rete fisica, che consente la consegna diretta
tra le stazioni mediante una trasmissione broadcast. Serve solo
mappare indirizzi IP in indirizzi MAC con ARP e RARP.
(*) In realt la faccenda pu complicarsi se si vuole minimizzare lo
scambio di pacchetti in reti fisiche costituite da pi sottoreti fisiche
collegate da bridge. Alcuni bridge intelligenti monitorano il traffico
a livello 2, memorizzando gli indirizzi MAC contenuti nei campi
provenienza dei pacchetti di livello 2 che li attraversano. In tal
modo capiscono automaticamente in che direzione sono collocati gli
hosts con quei MAC address, ed instradano i pacchetti MAC ad
essi destinati solo in quella direzione. I pacchetti broadcast sono
invece propagati a tutti.
Il routing tra le subnet, cio allinterno di un autonomous system
gestito dai router (detti Interior Router), mediante tabelle di
instradamento che possono essere scritte (in toto o in parte)
manualmente dal gestore della rete o calcolate automaticamente con
algoritmi dei cosiddetti tipi distance vector o link state packet. Tra i
pi recenti ricordiamo OSPF (Open Shortest Path First) che effettua
il bilanciamento di carico tra percorsi paralleli ed e standard.
Il routing tra autonomous systems risponde pi ad esigenze
amministrative che non tecniche, ed gestito con algoritmi
detti Exterior Gateway Protocol, quali BGP (Border Gat. Prot.).
66
Routing Gerarchico
Una connessione TCP
viene instaurata con
le seguenti fasi,
che formano il
Three-Way
Handshake (perch
formato da almeno
3 pacchetti trasmessi):
1) il server si predispone ad accettare una richiesta di connessione,
mediante le chiamate a socket, bind, listen e infine accept che realizza
una apertura passiva (passive open) cio senza trasmissione di dati.
2) il client effettua le chiamate a socket, bind ed infine alla connect che
realizza una apertura attiva (active open) mediante la spedizione di un
segmento TCP detto SYN segment (synchronize) in cui settato ad 1
il flag syn, a zero il flag ack, e che trasporta un numero di sequenza
iniziale (J) che il numero di sequenza iniziale dei dati che il client
vuole mandare al server. Il segmento contiene un header TCP con i
numeri di porta ed eventuali opzioni su cui accordarsi, e di solito non
contiene dati. Il segmento viene incapsulato in un datagramIP.
3) Il server deve rispondere al segmento SYN del client spedendogli un
segmento SYN (flag syn settato ad 1) con il numero di sequenza
iniziale (K) dei dati che il server vuole mandare al client in quella
connessione. Il segmento presenta inoltre nel campo Ack number il
valore J+1 che indica che si aspetta di ricevere J+1, e presenta il flag
ack settato ad 1, per validare il campo Ack number.
4) il client, ricevendo il SYN del server con lAck numer J+1 sa che la
sua richiesta di connessione stata accettata, e dal sequence number
ricevuto K capisce che i dati del server inizieranno da K+1, quindi
risponde con un segmento ACK (flag syn settato a zero e flag ack
settato a 1) con Ack number K+1, e termina la connect.
5) al ricevimento dellACK K+1 il server termina la accept.
Setup delle ConnessioniTCP
87
J+... J+3 J+2 J+1
K+1 K+2 K+3 K+...
Ogni segmento di tipo SYN pu contenere delle opzioni, che servono a
stabilire alcune caratteristiche della connessione che si sta instaurando.
Tra le pi importanti ricordiamo:
1) MSS options: con questa opzione il TCP che manda il proprio SYN
annuncia il maximum segment size, la pi grande dimensione di
segmento che in grado di ricevere. Lopzione TCP_MAXSEG resa
disponibile dallinterfaccia socket, consente di settare questa opzione.
2) Windows scale options: la finestra scorrevole pi grande che due
TCP possono concordare 65535, perch il campo Window Size
occupa 16 bit. Per situazioni in cui il collegamento a larghissima
banda ma con grande ritardo di trasmissione (es. via satellite) una
dimensione di finestra pi grande rende pi veloce la trasmissione di
grandi quantit di dati. Per identificare finestre pi grandi nellheader
TCP, si setta questa opzione che indica di considerare il campo
Window Size dopo averlo shiftato a sinistra di un numero di posizione
compreso tra 0 e 14, in modo da moltiplicare la Window Size di un
fattore fino a 2 elevato alla 14, ovvero in modo da raggiungere valori
dellordine del GigaByte. Lopzione SO_RECVBUF resa disponibile
dallinterfaccia socket, consente di settare questa opzione.
Opzioni TCP nel Setup
88
89
(1)
(2.1)
(2.2)
(3)
(4)
Una connessione TCP viene chiusa mediante un protocollo composto da
quattro messaggi trasmessi:
1) una delle applicazioni su un end-system(chiamiamola attiva)
effettua la chiusura attiva (active close) chiamando la funzione close()
che spedisce un segmento FIN (flag FIN settato a 1), con un numero di
sequenza M pari allultimo dei byte trasmessi in precedenza pi uno.
Con ci si indica che viene trasmesso un ulteriore dato, che il FIN
stesso. Per convenzione il FIN pensato avere dimensione pari ad 1
byte, quindi lend-systemattivo si aspetta di ricevere per il FIN un ACK
con Ack Number pari a M+1.
2) lend systemche riceve il FIN (chiamiamolo passivo) effettua la
chiusura passiva (passive close) allinsaputa dellapplicazione.
2.1) Per prima cosa il modulo TCP del passivo spedisce allend-system
attivo un segmento ACK con Ack number pari a M+1, come riscontro
per il FIN ricevuto.
2.2) Poi il TCP passivo trasmette allapplicazione padrona di quella
connessione il segnale FIN, sotto forma di end-of-file che viene
accodato ai dati non ancora letti dallapplicazione. Poiche la ricezione
del FIN significa che non si ricever nessun altro dato, con lend-of-file
il TCP comunica allapplicazione che lo streamdi input chiuso.
Terminazione delle (1)
ConnessioniTCP
end-system
attivo
end-system
passivo
3) Quando lapplicazione del passivo finalmente legge dal buffer
lend-of-file (con una read() che restituisce 0), deve effettuare per quel
socket la chiamata alla funzione close(). La close() ordina al modulo
TCP di inviare a sua volta allend-systemattivo un segmento FIN,
col numero di sequenza (N) del FIN, cio lultimo byte trasmesso pi 1.
4) il modulo TCP dellattivo, quando riceve il FIN spedisce un ACK
con Ack number N+1, cio il numero di sequenza del successivo al
FIN, cio il FIN pi uno, poich 1 per convenzione la dimensione del
FIN. Terminato questo passo viene conclusa anche la funzione close()
dellattivo.
Chiusura attiva o passiva non dipendono dallessere client o server,
ma solo da chi per primo effettua la chiamata alla funzione close().
Notare che i due segmenti dal passivo allattivo degli step 2.1 e 2.2
(ACK M+1 e FIN N rispettivamente) potrebbero essere combinati in un
solo messaggio a seconda del comportamento del passivo.
Unulteriore variazione, di carattere opposta alla precedente, che tra
gli step 2.1 e 2.2 il passivo ha ancora la possibilit di inviare dei dati
verso lattivo, perch al momento dello step 2.1 stata effettuata,
mediante il FIN, una chiusura del flusso solo nella direzione dallattivo
al passivo, chiusura che viene detta half-close.
Terminazione delle (2)
ConnessioniTCP
90
Esempio di connessione TCP (1)
93
Vediamo i segmenti scambiati e gli stati assunti da client e server in una
connessione TCP in cui il client chiede un servizio ed il server risponde.
Il client inizia e specifica lopzione Maximum Segment Size di 1460
byte, il server risponde e specifica una diversa richiesta di MSS di 1024.
La MSS pu essere diversa nelle due direzioni. Stabilita la connessione
il client spedisce una richiesta al server nei dati di un solo segmento. Il
server risponde spedendo la risposta nei dati di un solo segmento.
Notare che, per diminuire il numero di segmenti scambiati, assieme alla
risposta il server spedisce nel segmento anche lACK per il segmento
ricevuto. Tale tecnica, detta piggybacking, viene utilizzata quando il
ritardo nella risposta inferiore ai 200 msec. Infine vengono utilizzati
quattro segmenti per effettuare la terminazione della connessione.
Il compito del livello transport (livello 4) di fornire un trasporto
efficace dall'host di origine a quello di destinazione,
indipendentemente dalla rete utilizzata.
Questo il livello in cui si gestisce per la prima volta (dal basso
verso l'alto) una conversazione diretta, cio senza intermediari, fra
una transport entity su un host e la sua peer entity su un
altro host.
.
Naturalmente, tali servizi sono realizzati dal livello transport per
mezzo dei servizi ad esso offerti dal livello network.
Cos come ci sono due tipi di servizi di livello network, ce ne
sono due anche a livello transport:
servizi affidabili orientati alla connessione, detti di tipo
stream, offerti dal TCP (Transmission Control Protocol);
servizi senza connessione detti di tipo datagram offerti
dall UDP (User Datagram Protocol).
Il livello di Trasporto del TCP/IP
67
TSAP
address
NSAP
address
Liv.
Applic.
Liv.
Transport
Liv.
Network
Transport
Entity
Transport
Entity
TPDU
Quando si vuole trasferire una o pi TPDU (Transport Protocol Data
Unit) da una sorgente ad una destinazione di livello 4, occorre
specificare mittente e destinatario di livello 4. Il protocollo di livello 4
deve quindi decidere come deve essere fatto l'indirizzo di livello
transport, detto TSAP address (Transport Service Access Point
address).
Poich lindirizzo di livello 4 serve a trasferire informazioni tra
applicazioni che lavorano su hosts diversi, deve poter individuare un
host e una entit contenuta nellhost. Per questo motivo i protocolli di
livello 4 tipicamente definiscono come indirizzo di livello 4 una coppia
formata da un indirizzo di livello network che identifica lhost, e da
unaltra informazione che identifica un punto di accesso in quellhost
(NSAP address, informazione supplementare).
Ad esempio, in TCP/IP un TSAP address (ossia un indirizzo TCP o
UDP) ha la forma:
( IP address : port number )
Port number un intero a 16 bit, che identifica un servizio o un punto
di accesso e/o smistamento di livello 4.
Ad es. la coppia (137.204.72.49 : 23) indica la porta 23 dellhost
poseidon.csr.unibo.it, cio lentry point per il demone telnet, cio il
punto di accesso allapplicazione che permette ad un utente di
collegarsi mediante telnet allhost poseidon.
Anche se lindirizzo di livello trasporto formato da questa coppia, il
TCP/IP, per ridurre loverhead causato dagli header dei vari livelli,
nella trasmissione effettua una violazione della stratificazione tra i
livelli 4 e 3 (Trasporto e Network). Infatti, come vedremo TCP e UDP
contengono nei loro header solo i numeri delle porte e riutilizzano
gli indirizzi IP di mittente e destinaz. contenuti nel pacchetto IP.
Indirizzi a livello di Trasporto
per il TCP/IP
68
Gli identificatori di porta (port number) permettono di
effettuare la demultiplazione dei pacchetti di livello 4, ovvero di
discriminare lapplicazione destinazione dei pacchetti in funzione
del port number contenuto nellheader del pacchetto di livello
transport, sia esso di tipo TCP che UDP.
E ovvio che mittente e destinatario devono essere daccordo sul
valore della porta del destinatario per poter effettuare la
trasmissione.
Il mittente scrive questo numero di porta come indirizzo del
destinatario, ed il destinatario si deve mettere in attesa dei
pacchetti che giungono allhost del destinatario e che posseggono
come identificatore proprio quel port number.
Alcune primitive fornite dallinterfaccia socket permettono di
specificare il numero di porta di cui interessa ricevere i pacchetti
(stream=flussi di dati nel caso TCP). E quindi il sistema operativo
che si fa carico di effettuare le operazioni di demultiplexing dei
pacchetti ricevuti dal livello network.
Multiplexing a livello Trasporto
69
Il livello transport fornisce un protocollo per il trasporto di
blocchi di dati non connesso e non affidabile, detto UDP (User
Datagram Protocol), che utilizza lIP per trasportare messaggi,
che molto simile allIP in termini di risultato del trasporto, ed
offre in pi rispetto allIP la capacit di distinguere tra pi
destinazioni allinterno di uno stesso host, mediante il meccanismo
delle porte.
Ogni Datagram UDP viene incapsulato in un datagram IP, quindi
la dimensione del datagram UDP non pu superare la dimensione
massima della parte dati del datagram IP. Il datagram IP pu
essere frammentato se la MTU piccola.
LUDP non usa dei riscontri per verificare se un messaggio
arrivato a destinazione, non ordina i messaggi arrivati, e non fornisce
nessun tipo di controllo sulla velocit di trasmissione dei dati. Quindi i
datagram UDP possono essere persi, duplicati o arrivare fuori ordine.
Utilizzano UDP alcuni protocolli standard, a cui sono riservati dei
numeri di porte predefiniti, in modo da poter essere rintracciati nello
stesso punto (punto daccesso) su tutti gli hosts. Ricordiamo tra gli
altri: nameserver (server di nomi di dominio, porta 53), bootps
(server del protocollo di bootstrap, 67), tftp (Trivial File Transfer, 69),
ntp (Network Time protocol, 123).
Il protocollo di Trasporto UDP
(User Datagram Protocol)
70
IP header UDP header UDP data
20 bytes 8 bytes
UDP datagram
IP datagram
Il pacchetto UDP costituito da un header e da una parte dati.
Lheader UDP composto da 4 campi:
i primi due sono i numeri di porta del mittente e del destinatario
del datagram, ciascuno di 16 bit.
il terzo la lunghezza dei dati del datagram UDP, in byte.
lultimo un checksum per il controllo derrore, che per
opzionale. Un valore zero in questo campo indica che la chesksum
non stata calcolata
Si noti che non ci sono gli indirizzi IP di mittente e destinatario.
A differenza dellheader IP, il checksum contenuto nellheader
UDP considera anche la parte dati UDP.
Inoltre il calcolo della checksum viene effettuato ponendo in testa
al datagram UDP una pseudointestazione (che non viene
trasmessa), con gli indirizzi IP di provenienza e destinazione
ricavata dallheader IP in cui lUDP viene trasportato,
pseudointestazione fatta in questo modo:
Il motivo di questo modo di computare la checksum verificare a
livello UDP, che il datagram UDP abbia raggiunto la corretta
destinazione IP, che non compare nellheader UDP.
Formato del Datagram UDP
71
0 15 16 31
source port number destination port number
checksum UDP length UDP
UDP data
UDP
header
0 15 16 31
source IP address
UDP datagram length
UDP
pseudo
header
destination IP address
8-bit protocol (17)
zero
esempio di trasmissione
di datagram UDP
72
Senza per ora entrare nei dettagli riguardanti i socket, vediamo un
semplice esempio di programma che sfrutta i socket per trasmettere un
datagram UDP contenente una stringa di testo pippo da un host
sender 137.204.72.49 ad un host receiver 130.136.2.7 .
Il punto di accesso stabilito dal programmatore nel receiver, nella porta
UDP caratterizzata dal numero 3001.
Il receiver si mette in attesa sulla porta 3001 fino a che il sender invia
un datagram allhost receiver su quella porta, e stampa il contenuto del
datagram ricevuto.
Quindi sender e receiver devono essersi messi daccordo sulla porta da
usare, ed il sender deve conoscere lindirizzo IP del receiver.
Il codice completo (con la gestione degli errori) dei due programmi
che realizzano lesempio qui mostrato disponibile allo indirizzo
http://www.cs.unibo.it/~ghini/didattica/sistemi3/UDP1/UDP1.html
data link
physical
network
transport
application
3001
receiver
130.136.2.7
media
data link
physical
network
transport
application
sender
137.204.72.49
data
punto
daccesso
esempio: receiver di datagram UDP
73
/* eseguito sullhost 130.136.2.7 */
#define SIZEBUF 10000
void main(void) {
struct sockaddr_in Local, From; short int local_port_number=3001;
char string_remote_ip_address[100]; short int remote_port_number;
int socketfd, OptVal, msglen, Fromlen; char msg[SIZEBUF];
/* prende un socket per datagram UDP */
socketfd = socket (AF_INET, SOCK_DGRAM, 0);
/* impedisce l'errore di tipo EADDRINUSE nella bind() */
OptVal = 1;
setsockopt (socketfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&OptVal, sizeof(OptVal) );
/* assegna l'indirizzo IP locale e una porta UDP locale al socket */
Local.sin_family = AF_INET;
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_port = htons(local_port_number);
bind ( socketfd, (struct sockaddr*) &Local, sizeof(Local));
/* wait for datagram */
Fromlen=sizeof(struct sockaddr);
msglen = recvfrom ( socketfd, msg, (int)SIZEBUF, 0,
(struct sockaddr*)&From, &Fromlen);
sprintf((char*)string_remote_ip_address,"%s",inet_ntoa(From.sin_addr);
remote_port_number = ntohs(From.sin_port);
printf("ricevuto msg: \"%s\" len %d, from host %s, port %d\n",
msg, msglen, string_remote_ip_address, remote_port_number);
}
esempio: sender di datagram UDP
74
/* eseguito sullhost 137.204.72.49 */
int main(void) {
struct sockaddr_in Local, To; char msg[]=pippo";
char string_remote_ip_address[]="130.136.2.7";
short int remote_port_number = 3001;
int socketfd, OptVal, addr_size;
/* prende un socket per datagram UDP */
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
/* impedisce l'errore di tipo EADDRINUSE nella bind() */
OptVal = 1;
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&OptVal, sizeof(OptVal));
/* assegna l'indirizzo IP locale e una porta UDP locale al socket */
Local.sin_family = AF_INET;
/* il socket verra' legato all'indirizzo IP dell'interfaccia che verr
usata per inoltrare il datagram IP, e ad una porta a scelta del s.o. */
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_port = htons(0); /* il s.o. decide la porta locale */
bind( socketfd, (struct sockaddr*) &Local, sizeof(Local));
/* assegna la destinazione */
To.sin_family = AF_INET;
To.sin_addr.s_addr = inet_addr(string_remote_ip_address);
To.sin_port = htons(remote_port_number);
addr_size = sizeof(struct sockaddr_in);
/* send to the address */
sendto(socketfd, msg, strlen(msg) , 0,
(struct sockaddr*)&To, addr_size);
}
Il protocollo di Trasporto TCP
(Transmission Control Protocol)
75
Il protocollo TCP stato progettato per fornire un flusso di byte da
sorgente a destinazione full-duplex, affidabile, su una rete non
affidabile.
Dunque, offre un servizio reliable e connection oriented, e si
occupa di:
stabilire la connessione full duplex tra due punti di accesso a
livello trasporto;
accettare dati dal livello application eventualmente
bufferizzando in input;
a richiesta, forzare linvio interrompendo la bufferizzazione;
spezzare o accorpare i dati in segment, il nome usato per i TPDU
(Transport Protocol Data Unit) aventi dimensione massima 64
Kbyte, ma tipicamente di circa 1.500 byte;
consegnarli al livello network, per effettuare la trasmissione
allinterno di singoli datagram IP, eventualmente ritrasmettendoli;
ricevere segmenti dal livello network;
rimetterli in ordine, eliminando buchi e doppioni;
consegnare i dati, in ordine, al livello application.
chiudere la connessione.
Il servizio effettua internamente la gestione di ack, il controllo del
flusso e il controllo della congestione.
Il servizio del TCP di tipo orientato allo stream, ovvero
trasporta un flusso di byte, il che significa che se anche la sorgente
spedisce (scrive sul device) i dati a blocchi (es 1 KB poi 3 KB poi
ancora 2 KB) la connessione non informa la destinazione su come
sono state effettuate individualmente le scritture; la destinazione
potrebbe ad es. leggere i dati a blocchi di 20 byte per volta.
Come lUDP, il TCP impiega numeri di porta di protocollo per
identificare la destinazione finale allinterno di un host.
La situazione per molto diversa rispetto allUDP, in cui
possiamo immaginare ogni porta come una sorta di coda a cui
arrivano dei datagram delimitati, provenienti ciascuno da un mittente
eventualmente diverso.
Per il TCP si vuole invece che una connessione sia dedicata in
esclusiva ad una coppia di applicazioni risiedenti su macchine
diverse. Il TCP impiega la connessione (virtuale), non la porta di
protocollo, come sua astrazione fondamentale;
le connessioni sono identificate da una coppia di punti
daccesso (endpoint) detti socket, uno su ciascuna macchina.
Ogni socket caratterizzato da una coppia ( IP address: Port
number) che pu essere utilizzata da pi processi simultaneamente.
Questa ad esempio la situazione prodotta dal processo demone del
telnet (telnetd) che consente agli utenti di una macchina unix A di
collegarsi ad A da unaltro host accedendo tutti alla stessa porta TCP
numero 23 di quellhost A. Tutte le connessioni condividono quindi
la stessa coppia (IP_A, 23).
Per ciascuna connessione viene univocamente individuata
dalla coppia di socket dei due host A e B implicati nella
connessione, ovvero dalla terna:
( IP address A: Port number A , IP address B: Port number B )
Pi utenti che effettuano tutti il telnet da una stessa macchina B
verso una stessa macchina A instaurano connessioni identificate da
terne del tipo ( IP_A : 23 , IP_B : tcp_port_B ) con tcp_port_B
tutti diversi, e quindi con connessioni univocamente
determinate.
Indirizzamento nel TCP (1)
76
Come per il caso UDP, anche per il TCP esistono dei port number
che sono riservati ad uso di protocolli standard, e vengono detti
well-know-port. Queste porte sono quelle con valore inferiore a 256.
Port Number Service
20 Ftp (control)
21 Ftp (data)
23 Telnet
25 Smtp
80 Http
I segmenti TCP
Lunit di trasferimento del TCP detta segmento, e viene usato
per stabilire connessioni, per trasferire dati, per inviare riscontri (una
sorta di ricevuta di ritorno), per dimensionare le finestre scorrevoli e
per chiudere le connessioni.
TCP usa un meccanismo di sliding window (finestre scorrevoli) di
tipo go-back-n con timeout. Se questo scade, il segmento si
ritrasmette. Si noti che le dimensioni della finestra scorrevole e i
valori degli ack sono espressi in numero di byte, non in
numero di segmenti.
ogni byte del flusso TCP numerato con un numero d'ordine a 32
bit, usato sia per il controllo di flusso che per la gestione degli ack;
ogni segmento TCP non pu superare i 65.535 byte, e viene
incluso in un singolo datagram IP;
un segmento TCP formato da:
uno header, a sua volta costituito da:
- una parte fissa di 20 byte;
- una parte opzionale;
i dati da trasportare;
Well-Know-Port nel TCP
77
Formato del segmento TCP
78
Source port, destination port: identificano gli end point (locali ai
due host) della connessione. Essi, assieme ai corrispondenti numeri
IP, identificano la connessione a cui appartiene il segmento;
Sequence number: la posizione del primo byte contenuto nel
campo dati allinterno dello stream di byte che il trasmettitore
del segmento invia (si possono inviare quindi al max 4 miliardi di
byte circa in uno stesso stream).
Ack. number: la posizione del prossimo byte aspettato allinterno
del segmento inviato dal ricevitore del presente segmento.
TCP header length: lunghezza del segmento misurata in parole di
32 bit (necessario perch il campo options ha dimensione variabile).

Destination port
Sequence number
32 bit
Source port
Ack. number
TCP
header len
U
R
G
A
C
K
P
S
H
R
S
T
S
Y
N
F
I
N Window size
Options (zero o pi parole di 32 bit)
Urgent pointer Checksum
Dati (opzionali)
reserved
Checksum, simile a quello di UDP, verifica che sia lheader che i
dati del segmento siano arrivati a destinazione senza errori. Come
per UDP il calcolo del checksum prevede che sia aggiunto in testa al
segmento uno pseudoheader contenente gli indirizzi IP di sorgente e
destinazione, la lunghezza del segmento, estratti dallheader del
datagram IP che contiene il segmento.
Nellheader del segmento TCP sono presenti inoltre 6 flags di un bit
ciascuno che servono per assegnare validit ad alcuni campi
dellheader o per segnalare richieste o conferme:
URG 1 se il campo urgent pointer usato, 0 altrimenti.
ACK 1 se l'ack number valido (cio se si trasporta un ack), 0
altrimenti.
PSH indica che questo segmento contiene dati urgenti (pushed
data), da consegnare senza aspettare che il buffer si riempia.
RST richiesta di reset della connessione (ci sono problemi!).
SYN usato nella fase di setup della connessione:
SYN=1 ACK=0 richiesta connessione;
SYN=1 ACK=1 accettata connessione.
FIN usato per rilasciare una connessione.
Formato del segmento TCP (2)
79
0 15 16 31
source IP address
TCP segment length
TCP
pseudo
header
destination IP address
8-bit protocol (=6)
0
altri campi presenti nel segmento TCP sono:
Window size: il controllo di flusso di tipo sliding window di
dimensione variabile. Window size dice quanti byte possono
essere spediti a partire da quello (compreso) che viene
confermato con l'ack number. Un valore zero significa: fermati
per un p, riprenderai quando ti arriver un uguale ack number con
un valore di window size diverso da zero. Questo valore serve a
ridurre la velocit di trasmissione dei dati nel flusso di byte che va
dal ricevente al trasmettitore del presente segmento. Viene usato
quando ci si accorge di una congestione della rete, per non
incrementare ancora la congestione, oppure quando i buffer di
ricezione sono ormai pieni e non si vuole rischiare di perdere dei
dati .
Urgent pointer puntatore ai dati urgenti, indica la posizione in
cui terminano i dati urgenti nello stream inviati dal trasmettitore.
Options contiene alcune opzioni appliccabili al flusso. Le pi
importante sono negoziabili durante il setup della connessione, e
sono:
dimensione massima dei segmenti da spedire (MSS: Maximum
Segment Size), serve se uno degli host ha dei buffer molto limitati
ma soprattutto per adattare il segmento alla MTU della rete che
collega i due host, in modo che ogni segmento venga incluso in un
datagram IP che non debba essere frammentato;
uso di selective repeat invece che go-back-n (un diverso algoritmo
di controllo del flusso);
uso di NAK.
Formato del segmento TCP (3)
80
Laffidabilit del TCP si basa sulla combinazione di alcune tecniche
che adesso analizzeremo separatamente. La tecnica pi semplice per
garantire che tutti i byte trasmessi in un flusso giungano a
destinazione nota come riscontro positivo con ritrasmissione.
Quando un ricevitore riceve un pacchetto risponde al pacchetto
inviando un riscontro (acknowledgment, ACK) al trasmettitore
per confermare di averlo ricevuto.
Quando il trasmettitore deve inviare un pacchetto, nel momento
in cui lo spedisce ne mantiene una copia e fa partire un timer.
Se allo scadere del timer non ha ancora ricevuto il relativo ACK
ritrasmette il pacchetto.
Trasmissione affidabile: riscontro
positivo con ritrasmissione (1)
81
Poich pu capitare che la rete duplichi un pacchetto, pu capitare di
ricevere un ACK per un pacchetto che era gi stato riscontrato in
precedenza, e di scambiarlo per un riscontro di un successivo
pacchetto per cui attendevamo un ACK.
Per ovviare al problema dei riscontri duplicati, i pacchetti vengono
numerati sequenzialmente, e lACK contiene il numero
sequenziale del pacchetto che vuole riscontrare.
Le finestre Scorrevoli (1)
Il meccanismo di riscontro positivo rallenta la trasmissione, perch
il trasmettitore deve attendere il riscontro di ciascun pacchetto
prima di inviare il successivo, quindi i pacchetti viaggiano in rete
in una sola direzione per volta, e la rete sottoutilizzata mentre gli
end system attendono le risposte, che possono ritardare.
La tecnica delle finestre scorrevoli (Sliding Windows) invece
permette al trasmettitore di poter continuare ad inviare un certo
numero N (dimensione della finestra) di pacchetti successivi
allultimo per cui ha ricevuto il riscontro, ovvero permette di
trasmettere fino ad altri N pacchetti mentre si in attesa di ricevere
il riscontro di un pacchetto precedentemente inviato. In tal modo la
rete viene utilizzata anche nei periodi di attesa.
In figura vengono
trasmessi 3 pacchetti
prima di ricevere un
riscontro.
Trasmissione affidabile: riscontro
positivo con ritrasmissione (2)
82
definiamo non riscontrato un pacchetto trasmesso per il quale non
ancora stato ricevuto il riscontro.
La finestra del trasmettitore inizia col primo pacchetto non
riscontrato. I pacchetti successivi, che stanno dentro alla finestra,
possono essere trasmessi, mentre i pacchetti che seguono la finestra
non possono essere trasmessi.
Quando un pacchetto P (trasmesso) nella finestra viene riscontrato
(il pacchetto 6 in figura) (e sono riscontrati anche i suoi precedenti)
allora la finestra avanza fino al pacchetto successivo a P,
consentendo di trasmettere i pacchetti che sono entrati nella finestra.
(in figura la dimensione della finestra 8)
Le finestre Scorrevoli (2)
83
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
pacchetti
trasmessi
e riscontrati
primo pacchetto
non riscontrato
pacchetti trasmissibili
pacchetti
non ancora
trasmissibili
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
pacchetti
trasmessi
e riscontrati
primo pacchetto
non riscontrato
pacchetti trasmissibili
pacchetti
non ancora
trasmissibili
pacchetti
riscontrati
nuovi pacchetti
trasmissibili
le finestre continuano a scorrere finch si ricevono riscontri,
permettendo di trasmettere i nuovi pacchetti che entrano nella
finestra.
Le prestazioni dei protocolli a finestra scorrevole dipendono dalla
dimensione della finestra e dalla velocit della rete.
se la dimensione della finestra 1, si ritorna allalgoritmo di
riscontro positivo.
allaumentare della dimensione della finestra diminuisce il periodo
di non utilizzo della rete.
con un opportuna scelta della dimensione della finestra possibile
mantenere la rete satura di pacchetti senza congestionarla.
Per ogni pacchetto trasmesso viene comunque ancora fatto partire
un timer, allo scadere del quale, se non ancora stato ricevuto il
riscontro, il pacchetto deve essere ritrasmesso.
Il meccanismo delle finestre scorrevoli stato spiegato riferendosi
alla trasmissione di pacchetti, ma vale ugualmente se:
1) consideriamo lo stesso meccanismo (la finestra) replicato nei
due end system, perch essendo la connessione TCP bidirezionale,
ogni host funge da trasmettitore;
2) al posto dei pacchetti consideriamo i byte del flusso realizzato
dalla connessione TCP, e utilizziamo la posizione dei byte nel flusso
come indicatore per sapere nel trasmettitore:
- qual il primo byte della finestra (da riscontrare)
- qual il primo byte che segue la finestra (da non trasmettere)
- qual il primo byte ancora da trasmettere dentro la finestra.
Le finestre Scorrevoli (3)
84
4 5 6 7 8 9 10 11 12 13 14 15
primo pacchetto
non riscontrato
pacchetti non
ancora trasmissibili
primo pacchetto
da trasmettere
Poich il TCP invia i dati in segmenti di lunghezza variabile, e
poich i segmenti ritrasmessi possono includere pi dati
delloriginale, i riscontri non possono fare riferimento facilmente ai
datagrammi o ai segmenti, ma fanno riferimento alla posizione dei
byte nello stream.
Il ricevitore raccoglie i byte di dati dei segmenti in arrivo e li
riordina, ma poich i segmenti viaggiano in datagram IP possono
essere persi o consegnati disordinatamente, generando dei buchi
nella ricostruzione.
Il ricevitore riscontra solo i byte che precedono il primo buco,
o meglio, specifica il valore sequenziale (la posizione) del primo
byte che ancora gli manca e che si aspetta di ricevere, il primo
byte del primo buco, anche se ha gi ricevuto qualcosa di
successivo.
Il vantaggio che questi riscontri cumulativi sono facili da
generare, e che la perdita di un riscontro non costringe alla
ritrasmissione se arriva un riscontro per un byte successivo.
Uno svantaggio che il trasmettitore, se un riscontro per un byte
non arriva, non in grado di capire se manca solo un pezzetto (un
buco anche di quel solo byte) o manca tutto da quel byte in avanti, e
ricomincia a trasmettere tutto da quel byte.
I Riscontri (1)
85
4 5 6 7 8 9 10 11 12 13 14 15
primo byte
non riscontrato
il trasmettitore ritrasmette tutto, da 7 a 13,
anche se il ricevitore ha gi tutto da 8 a 13
byte gia ricevuti
ma non riscontrati
Socket per TCP:
Fondamenti
Molte applicazioni di rete sono formate da due programmi distinti
(che lavorano su due diversi host) uno detto server ed uno detto client.
Il server si mette in attesa di una
richiesta da servire, il client
effettua tale richiesta.
Tipicamente il client comunica con
un solo server, mentre un server
usualmente comunica con pi
client contemporaneamente (su
connessioni diverse nel caso tcp).
Inoltre spesso client e server sono
processi utente, mentre i protocolli
della suite TCP/IP fanno solitamente parte del sistema operativo.
Nel seguito faremo riferimento al termine IP nel senso di IPv4.
Unix Standards
Posix = Portable Operating System Interface una famiglia di
standard (vedi http://www.pasc.org/standing/sd11.html) sviluppata da
IEEE e adottata da ISO. Posix comprende IEEE Std 1003.1 (1996)
(una raccolta di alcune specifiche precedenti) che contiene al suo
interno una parte detta Part1: System Application Program Interface
(API) che specifica linterfaccia C per le chiamate di sistema del
kernel Unix, relative a processi (fork, exec, signal, timer, user ID,
gruppi), files e directory (I/Ofunction), I/O da terminale, password, le
estensioni per il realtime, execution scheduling, semaphores, shared
memory, clock, message queues. In particolare comprende IEEE Std
1003.1g: Protocol Independent Interface (PII) che lo standard per
linterfaccia di programmazione delle reti, e definisce due standard
chiamati DNI (Detailed Network Interfaces):
1) DNI/Socket basato sulle API socket del 4.4BSD, di cui ci
occuperemo
2) DNI/XTI, basato sulle specifiche XPG4 del consorzio X/Open
Network Applications
86
Per primo viene fatto partire il server, poi viene fatto partire il client che
chiede la connessione al server e la connessione viene instaurata.
Nellesempio (ma non obbligatorio) il client spedisce una richiesta al
server, questo risponde trasmettendo alcuni dati. Questa trasmissione
bidirezionale continua fino a che uno dei due (il client nellesempio)
decide di interrompere la connessione,
e tramite la close() chiude la
connessione. Infine il server
chiude a sua volta la connessione.
Interazioni tra Client e Server TCP
104
ephemeral
port
Vediamo un semplice esempio di programma che sfrutta i socket TCP
per instaurare una connessione tra un client e un server, trasmettere dal
client al server una stringa di caratteri, aspettare che il server modifichi
questi caratteri (tranne lultimo, lo\0 che delimita la stringa)
shiftandoli di due posizioni (es: a diventa c, 2 diventa 4) e li
rispedisca indietro cos traslati, infine stampare il risultato.
Il server lhost 130.136.2.7, mentre il client lhost 137.204.72.49.
Il punto di accesso del servizio di traslazione la porta TCP 5001.
Il codice completo (con la gestione degli errori) dei due programmi
che realizzano lesempio qui mostrato disponibile allo indirizzo
http://www.cs.unibo.it/~ghini/didattica/sistemi3/TCP1/TCP1.html
esempio di trasmissione con TCP
114
data link
physical
network
TCP
transport
application
5001
server
130.136.2.7
media
data link
physical
network
TCP
transport
application
client
137.204.72.49
write
traslazione
caratteri
buf[i]=buf[i]+2
read
write read
/* servTCP.c eseguito sullhost 130.136.2.7 */
void main(void) {
struct sockaddr_in Local, Client; short int local_port_number=5001;
char buf[SIZEBUF]; int sockfd, newsockfd, n, nread, nwrite, len;
/* prende un socket per streamTCP */
sockfd = socket (AF_INET, SOCK_STREAM, 0);
/* collega il socket ad un indirizzo IP locale e una porta TCP locale */
memset ( &Local, 0, sizeof(Local) );
Local.sin_family = AF_INET;
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_port = htons(local_port_number);
bind ( sockfd, (struct sockaddr*) &Local, sizeof(Local));
/* accetta max 10 richieste simultanee di inizio conness., da adesso */
listen(sockfd, 10 );
/* accetta la prima conness. creando un nuovo socket per la conness. */
newsockfd = accept(sockfd, (struct sockaddr*) &Cli, &len);
/* riceve la stringa dal client */
nread=0;
while( (n=read(newsockfd, &(buf[nread]), MAXSIZE )) >0) {
nread+=n;
if(buf[nread-1]=='\0') break; /* fine stringa */
}
/* converte i caratteri della stringa */
for( n=0; n<nread -1 ; n++) buf[n] = buf[n]+2;
/* spedisce la stringa traslata al client */
nwrite=0;
while((n=write ( newsockfd, &(buf[nwrite]),nread-nwrite)) >0 )
nwrite+=n;
/* chiude i socket */
close(newsocketfd); close(socketfd);
}
server TCP per lesempio
115
/* cliTCP.c eseguito sullhost 137.204.72.49 */
void main(void) {
struct sockaddr_in Local, Serv; short int remote_port_number=5001;
char msg[]="012345ABCD"; int sockfd , n, nread, nwrite, len
/* prende un socket per streamTCP */
sockfd = socket (AF_INET, SOCK_STREAM, 0);
/* collega il socket senza specificare indirizzo IP e porta TCP locali */
memset ( &Local, 0, sizeof(Local) );
Local.sin_family = AF_INET;
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_port = htons(0);
bind ( sockfd, (struct sockaddr*) &Local, sizeof(Local));
/* specifica lindirizzo del server, e chiede la connessione */
memset ( &Serv, 0, sizeof(Serv) );
Serv.sin_family = AF_INET;
Serv.sin_addr.s_addr = inet_addr ( string_remote_ip_address);
Serv.sin_port = htons(remote_port_number);
connect ( sockfd, (struct sockaddr*) &Serv, sizeof( Serv));
/* spedisce la stringa al server */
len = strlen(msg)+1; nwrite=0;
while((len>nwrite)&&(n=write(sockfd,&(msg[nwrite]),len-nwrite))>0))
nwrite+=n;
nread=0; /* riceve la stringa traslata dal server */
while( (n=read(sockfd, &( msg[nread]), MAXSIZE )) >0) {
nread+=n;
if(buf[nread-1]=='\0') break; /* fine stringa */
}
printf(%s\n, msg); /* stampa la stringa traslata */
/* chiude i socket e termina*/
close(sockfd);
}
client TCP per lesempio
116
Cominciamo la descrizione delle Socket API (Application program
Interface) dalla descrizione delle strutture usate per trasferire
indirizzi dallapplicazione al kernel (nelle funzioni bind, connect,
sendto) e dal kernel alle applicazioni (nelle funzioni accept, recvfrom,
getsockname e getpeername).
I dati definiti per Posix.1g sono quelli della seguente tabella:
int8_t signed 8-bit integer <sys/types.h>
uint8_t unsigned 8-bit integer <sys/types.h >
int16_t signed 16-bit integer <sys/types.h >
uint16_t unsigned 16-bit integer <sys/types.h>
int32_t signed 32-bit integer <sys/types.h>
uint32_t unsigned 32-bit integer <sys/types.h>
sa_family_t famiglia di indirizzi socket <sys/socket.h>
AF_INET per IPv4, AF_INET6 per IPv6,
AF_LOCAL per indir. locali unix (per pipe ecc..)
socklen_t lunghezza della struttura che
contiene lindirizzo,
di solito un uint32_t <sys/socket.h>
in_addr_t indirizzo IPv4, = uint32 <netinet/in.h>
in_port_t porta TCP o UDP, = uint16 <netinet/in.h>
Poich i socket devono fornire uninterfaccia per diverse famiglie di
protocolli (IPv4, IPv6 e Unix), e poich tali strutture vengono passate
per puntatore, le funzioni di libreria presentano un argomento che il
puntatore alla generica struttura (struct sockaddr*), ma essendo
diversa la struttura passata a seconda della famiglia di indirizzi usata,
largomento passato deve essere convertito mediante il cast alla struttura
(struct sockaddr*), ad es:
struct sockaddr_in server; /* IPv4 socket address structure */
memset ( &server, 0, sizeof(server) ); /* azzero tutta la struttura */
... riempimento dei dati della struttura server ...
bind ( socketfd, ( (struct sockaddr struct sockaddr *) *)&server, sizeof(server) );
Socket Address Structures (1)
96
La generica struttura dellindirizzo dunque cosi definita:
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
La famiglia di indirizzi Ipv4 (sa_family=AF_INET) usa la struttura:
struct sockaddr_in {
uint8_t sin_len; /* lunghezza struttura */
sa_family_t sin_family; /* = AF_INET */
in_port_t sin_port; /*16-bit TCP UDP port, network byte ordered */
struct in_addr sin_addr; /* 32-bit IPv4 address, network byte ordered */
char sin_zero[8]; /* unused */
};
con
struct in_addr { /* e una struttura per ragioni storiche */
in_addr_t s_addr ; /* 32-bit IPv4 address network byte ordered */
};
sa_len e sa_family si sovrappongono perfettamente a sin_len e
sin_family rispettivamente, permettendo di leggere la costante di tipo
sa_family_t e di capire che tipo di struttura si sta utilizzando.
il campo sin_len non richiesto espressamente da Posix.1g, , e anche
quando presente non necessario settarlo, se non per applicazioni di
routing, in quanto le principali funzioni in cui si passano indirizzi
prevedono gi un argomento in cui si passa (o riceve) la lunghezza della
struttura indirizzo.
Il campo sin_zero non usato, ma va sempre settato tutto a zero prima
di passare una struttura che lo contiene. Di pi, per convenzione,
bisogna sempre settare TUTTA la struttura indirizzo tutta a zero
prima di riempire i vari campi, usando la funzione memset().
memset ( &server, 0, sizeof(server) );
Socket Address Structures (2)
97
Confrontiamo alcune delle strutture usate per gli indirizzi:
Socket Address Structure (3)
98
Poich alcuni campi delle strutture di indirizzo (i numeri di porta o gli
indirizzi IPv4 ad esempio) devono essere memorizzati secondo lordine
per i bytes stabilito per la rete (network byte order), prima di assegnare
alla struttura un valore di porta (16-bit) o un indirizzo IPv4 (32-bit)
necessario convertirlo dallordine dei byte per lhost allordine per la
rete, utilizzando delle funzioni di conversione, i cui prototipi sono
definiti nellinclude <netinet/in.h>:
uint16_t htons (uint16_t host16bitvalue); /* Host TO Network Short */
uint32_t htonl (uint32_t host32bitvalue); /* Host TO Network Long */
Viceversa, per convertire il valore di una porta o di un indirizzo IPv4,
preso da una struttura di indirizzo, in un valore intero secondo
lordinamento dellhost si devono utilizzare le funzioni:
uint16_t ntohs (uint16_t net16bitvalue); /* Network TO Host Short */
uint32_t ntohl (uint32_t net32bitvalue); /* Network TO Host Long */
Se lordinamento dellhost corrispondente allordinamento di rete,
queste funzioni sono implementate con delle macro nulle, cio non
modificano il dato.
Funzioni di Manipolazione dei Byte
Vediamo solo le funzioni portabili ovunque perche sono ANSI C.
void *memset (void *dest, int c, size_t n_bytes);
setta al valore c un numero len di byte a partire da dest
void *memcpy (void *dest, const void *src, size_t n_bytes);
copia n_bytes byte da src a dest, problemi se ce sovrapposizione,
nel caso usare memmove. Resituisce dest.
void *memcmp (const void ptr1, const void *ptr2, size_t n_bytes);
confronta due vettori di n_bytes ciascuno, restituisce 0 se sono
uguali, diverso da zero se diversi.
Funzioni di Ordinamento dei Byte
99
Queste funzioni sono definite in <arpa/inet.h>
Le funzioni inet_aton e inet_addr convertono gli indirizzi IP da una
forma di stringa di caratteri ASCII decimali separati da punti del tipo
255.255.255.255, nella forma di interi a 32-bit ordinati secondo
lordinamento di rete.
int inet_aton (const char *str, struct in_addr *addrptr);
scrive nella locazione puntata da addrptr il valore a 32-bit,
nellordine di rete, ottenuto dalla conversione della stringa zero-
terminata puntata da str. Restituisce zero in caso di errore, 1 se
tutto va bene.
in_addr_t inet_addr (const char *str); NON VA USATA
restituisce il valore a 32-bit, nellordine di rete, ottenuto dalla
conversione della stringa zero-terminata puntata da str.
In caso di errori restituisce INADDR_NONE, e questo un casino,
perch INADDR_NONE un intero a 32 bit di tutti 1, che sarebbe
ottenuto come risultato della chiamata di inet_addr passandogli la
stringa 255.255.255.255 che lindirizzo valido di broadcast.
Per evitare confusione non deve essere usata.
Infine ce una funzione che effettua la conversione inversa, da interi a
32-bit network ordered verso stringhe ASCII decimali separate da punti.
char *inet_ntoa (struct in_addr addr);
scrive in una locazione di memoria statica (di cui restituisce un
puntatore) la stringa ASCII null-terminata di caratteri decimali
separati da punti corrispondeni allindirizzo IP a 32-bit, nellordine
di rete, contenuto nella struttura addr (che stranamente non un
puntatore). Occhio, questa funzione non rientrante, perch
memorizza il risultato in una locazione statica.
Funzioni di Conversione di Indirizzi IP
dalla forma dotted-decimal ASCII string
alla forma 32-bit network byte ordered
100
La prima azione per fare dellI/O da rete la chiamata alla funziona
socket() specificando il tipo di protocollo di comunicazione da utilizzare
(TCP con IPv4, UDP con IPv6, Unix domain stream protocol per usare
le pipe).
#include <sys/socket.h>
int socket (int family, int type, int protocol);
restituisce un descrittore di socket maggiore o uguale a zero, oppure -1
in caso di errore, e setta errno.
Largomento family specifica la famiglia di protocolli da utilizzare.
family descrizione
AF_INET IPv4 protocol
AF_INET6 IPv6 protocol
AF_LOCAL Unix domain protocols (ex AF_UNIX)
AF_ROUTE Routing socket
AF_ROUTE Key socket (sicurezza in IPv6)
Largomento type specifica quale tipo di protocollo vogliamo utilizzare
allinterno della famiglia di protocolli specificata da family.
type descrizione
SOCK_STREAM socket di tipo stream(connesso affidabile)
SOCK_DGRAM socket di tipo datagram
SOCK_DRAW socket di tipo raw (livello network)
Largomento protocol di solito settato a 0, tranne che nel caso dei
socket raw.
Non tutte le combinazioni di family e type sono valide. Quelle valide
selezionano un protocollo che verr utilizzato.
AF_KEY
AF_INET AF_INET6 AF_LOCAL AF_ROUTE
SOCK_STREAM TCP TCP esiste
SOCK_DGRAM UDP UDP esiste
SOCK_DRAW IPv4 IPv6 esiste
funzione socket()
105
La funzione connect() usata dal client TCP per stabilire la connessione
con un server TCP.
#include <sys/socket.h>
int connect (int socketfd, const struct sockaddr *servaddr,
socklen_t addrlen);
restituisce 0 se la connessione viene stabilita, -1 in caso di errore.
Largomento socketfd un descrittore socket ottenuto da una chiamata
alla funzione socket().
Largomento servaddr come visto in precedenza in realt per IPv4
un puntatore alla struttura sockaddr_in, e deve specificare lindirizzo
IP e il numero di porta del server da connettere.
Largomento addrlen specifica la dimensione della struttura dati che
contiene lindirizzo del server servaddr, viene di solito assegnata
mediante la sizeof(servaddr).
Il client non deve di solito specificare il proprio indirizzo IP e la
propria porta, perch queste informazioni non servono a nessuno.
Quindi pu chiedere al sistema operativo di assegnargli una porta TCP
qualsiasi, e come indirizzo IP lindirizzo della sua interfaccia di rete, o
dellinterfaccia di rete usata se ne ha pi di una. Quindi NON SERVE la
chiamata alla bind() prima della connect().
Nel caso di connessione TCP la connect inizia il protocollo three way
handshake spedendo un segmento SYN. La funzione termina o quando
la connessione stabilita o in caso di errore.
In caso di errore la connect restituisce -1 e la variabile errno settata a:
- ETIMEDOUT nessuna risposta al segmento SYN
- ECONNREFUSED il server risponde con un segmento RST (reset) ad
indicare che nessun processo server in attesa
(stato LISTEN) su quella porta
- EHOSTUNREACH o ENETUNREACH host non raggiungibile
- ed altri ancora.
funzione connect()
106
La funzione bind() collega al socket un indirizzo locale. Per TCP e
UDP ci significa assegnare un indirizzo IP ed una porta a 16-bit.
#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
restituisce 0 se tutto OK, -1 in caso di errore.
Largomento sockfd un descrittore ottenuto da una socket().
Largomento myaddr un puntatore alla struttura sockaddr_in, e
specifica leventuale indirizzo IP locale e leventuale numero di porta
locale a cui il sistema operativo deve collegare il socket.
Largomento addrlen specifica la dimensione della struttura myaddr.
Lapplicazione pu collegarsi o no ad una porta.
Di solito il server si collega ad una porta nota (well know port).
Fa eccezione il meccanismo delle RPC.
I client di solito non si collegano ad una porta con la bind.
In caso non venga effettuato il collegamento con una porta, il
kernel effettua autonomamente il collegamento con una porta
qualsiasi (ephemeral port) al momento della connect (per il client)
o della listen (per il server).
Lapplicazione pu specificare (con la bind) per il socket un indirizzo
IP di uninterfaccia dellhost stesso.
Per un TCP client ci significa assegnare il source IP address che
verr inserito negli IP datagram, spediti dal socket.
Per un TCP server ci significa che verranno accettate solo le
connessioni per i client che chiedono di connettersi proprio a
quellIP address.
Se il TCP client non fa la bind() o non specifica un IP address
nella bind(), il kernel sceglie come source IP address, nel momento
in cui il socket si connette, quello della interfaccia di rete usata.
Se il server non fa il bind con un IP address, il kernel assegna al
socket come indirizzo IP locale quello contenuto nellIP destination
address del datagramIP che contiene il SYN segment ricevuto.
107
funzione bind() (1)
Chiamando la bind() si pu specificare o no lindirizzp IP e la porta,
assegnando valori ai due campi sin_addr e sin_port della struttura
sockaddr_in passata alla bind come secondo argomento.
A seconda del valore otteniamo risultati diversi, che sono qui elencati,
nella tabella che si riferisce solo al caso:
IP_address port
sin_addr sin_port Risultato
wildcard 0 il kernel sceglie IP address e porta
wildcard nonzero il kernel sceglie IP address, porta fissata
Local IP Address 0 IP address fissato, kernel sceglie la porta
Local IP Address non zero IP address e porta fissati dal processo
Specificando il numero di porta 0 il kernel sceglie collega il socket ad
un numero di porta temporaneo nel momento in cui la bind()
chiamata.
Specificando la wildcard (mediante la costante INADDR_ANYper
IPv4) il kernel non sceglie lindirizzo IP locale fino a che o il socket
connesso (se TCP) o viene inviato il primo datagramper quel socket (se
UDP).
Lassegnazione viene fatta con le istruzioni:
struct sockaddr_in localaddr;
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_port = htons(port_number);
Se con la bind si lascia al kernel la scelta di IP address locale o port
number locale, una volta che il kernel avr scelto, si potr sapere quale
IP address e quale port number stato scelto mediante la funzione
getsockname().
108
funzione bind() (2)
La funzione listen chiamata solo dal TCP server e esegue due azioni:
1) ordina al kernel di far passare il socket dallo stato iniziale CLOSED
allo stato LISTEN, e di accettare richieste di inizio connessione per quel
socket, accodandole in delle code del kernel.
2) specifica al kernel quante richieste di inizio connessione pu
accodare al massimo per quel socket.
#include <sys/socket.h>
int listen (int socketfd, int backlog );
restituisce 0 se tutto OK, -1 in caso di errore.
Largomento socketfd un descrittore ottenuto da una socket().
Largomento backlog un intero che specifica quante richieste di
inizio connessione (sia connessioni non ancora stabilite, cio che non
hanno ancora raggiunto lo stato ESTABLISHED, sia connessioni
stabilite) il kernel pu mantenere in attesa nelle sue code.
Quando un segmento SYN arriva da un client, se il TCP verifica che
c un socket per quella richiesta, crea una nuova entry in una coda
delle connessioni incomplete, e risponde con il suo FIN+ACK secondo
il 3-way handshake. Lentry rimane nella coda fino a che il 3-way
terminato o scade il timeout.
Quando il 3-way termina normalmente, la connessione viene
instaurata, e la entry viene spostata in una coda delle connessioni
completate.
Quando il server chiama la accept, la prima delle entry nella coda
delle connessioni completate viene consegnata alla accept() che ne
restituisce lindice come risultato, ovvero restituisce un nuovo socket
che identifica la nuova connessione.
Se quando il server chiama la accept(), la coda delle connessioni
completate vuota, la accept resta in attesa.
Largomento backlog specifica il numero totale di entry dei due tipi di
code.
Solitamente si usa 5, per http daemon si usano valori molto grandi.
109
funzione listen()
La funzione accept chiamata solo dal TCP server e restituisce la
prima entry nella coda delle connessioni gi completate per quel
socket. Se la coda vuota la accept resta in attesa.
#include <sys/socket.h>
int accept (int socketfd, struct sockaddr *cli_addr,
socklen_t *ptraddrlen);
restituisce un descrittore socket >=0 se tutto OK, -1 in caso di errore.
Largomento socketfd un descrittore ottenuto da una socket() e in
seguito processato da bind() e listen(). E il cosiddetto listening socket,
ovvero il socket che si occupa di insturare le connessioni con i client che
lo richiedono, secondo le impostazioni definite dalla bind() e dalla
listen(). Tale listening socket viene utilizzato per accedere alla coda
delle connessioni instaurate come visto per la listen().
Largomento cli_addr un puntatore alla struttura sockaddr_in, su cui
la funzione accept scrive lindirizzo IP del client e il numero di porta
del client, con cui stata instaurata la connessione a cui si riferisce il
socket che viene restituito come risultato .
Largomento ptraddrlen un puntatore alla dimensione della struttura
cli_addr che viene restituita.
Se accept termina correttamente restituisce un nuovo descrittore di
socket che il connected socket, cio si riferisce ad una connessione
instaurata con un certo client secondo le regole del listening socket
socketfd passato come input. Il connected socket verr utilizzato per
scambiare i dati nella nuova connessione.
Il listening socket socketfd (il primo argomento) mantiene anche dopo
la accept le impostazioni originali, e pu essere riutilizzato in una nuova
accept per farsi affidare dal kernel una nuova connessione.
110
funzione accept()
La funzione close utilizzata normalmente per chiudere un descrittore
di file, utilizzata per chiudere un socket e terminare una connessione
TCP.
int close (int socketfd);
restituisce 0 se tutto OK, -1 in caso di errore.
Largomento socketfd un descrittore di socket.
Normalmente la chiamata alla close() fa marcare closed il socket, e
la funzione ritorna il controllo al chiamante. Il socket allora non pu pi
essere usato dal processo, ovvero non pu pi essere usato come
argomento di read e write.
Per il TCP continua ad utilizzare il socket trasmettendo i dati che
eventualmente stanno nel suo buffer interno, fino a che non sono stati
trasmessi tutti. In caso di errore (che impedisce questa trasmissione)
successivo alla close lapplicazione non se ne accorge e laltro end
systemnon ricever alcuni dei dati.
Esiste unopzione per (la SO_LINGER socket option) che modifica
il comportamento della close, facendo in modo che la close restituisca
il controllo al chiamante solo dopo che tutti i dati nei buffer sono
stati correttamente trasmessi e riscontrati.
Se un socket connesso sockfd condiviso da pi processi (padre e
figlio ottenuto da una fork), il socket mantiene il conto di quanti sono
i processi a cui appartiene. In tal caso la chiamata alla close(sockfd)
per prima cosa decrementa di una unit questo contatore, e non
innesca la sequenza FIN+ACK+FIN+ACK di terminazione della
connessione fino a che tale contatore maggiore di zero, perch
esiste ancora un processo che tiene aperta la connessione.
Per innescare veramente la sequenza di terminazione, anche se ci sono
ancora processi per quella connessione si usa la funzione shutdown().
111
funzione close()
La funzione getsockname serve a conoscere lindirizzo di protocollo
(IP e port number) dellhost locale associato ad un certo descrittore di
socket connesso.
int getsockname ( int socketfd, struct sockaddr *Localaddr,
socklen_t *ptr_addrlen );
restituisce 0 se tutto OK, -1 in caso di errore.
Il primo argomento socketfd un descrittore di socket connesso.
Il secondo argomento Localaddr un puntatore ad una struttura di tipo
sockaddr, in cui la funzione metter lindirizzo locale della connessione.
Il terzo argomento ptr_addrlen un puntatore ad intero in cui la
funzione metter la dimensione della struttura scritta.
Questa funzione viene utilizzata in varie situazioni:
In un client, dopo una connect se non stata effettuata la bind, e
quindi non si specificato nessun indirizzo: in tal caso getsockname
permette di conoscere lindirizzo IP e la porta assegnati dal kernel alla
connessione.
In un client dopo una bind in cui come port number stato
specificato il valore 0, con il quale si informato il kernel di scegliere
lui la porta. In tal caso la getsockname restituisce il numero di porta
locale assegnato dal kernel.
In un server multihomed, dopo una accept preceduta da una bind in
cui come indirizzo IP LOCALE stata messa la wildcard
INADD_ANY, ci una volta che si sia stabilita una connessione, la
getsockname permette al server di sapere quale indirizzo IP ha la propria
interfaccia di rete utilizzata per la connessione.
112
funzione getsockname()
La funzione getpeername serve a conoscere lindirizzo di protocollo (IP
e port number) dellhost remoto associato ad un certo descrittore di
socket connesso.
int getpeername ( int socketfd, struct sockaddr *Remoteaddr,
socklen_t *ptr_addrlen );
restituisce 0 se tutto OK, -1 in caso di errore.
Il primo argomento socketfd un descrittore di socket connesso.
Il secondo argomento Remoteaddr un puntatore ad una struttura di
tipo sockaddr, in cui la funzione metter lindirizzo remoto della
connessione.
Il terzo argomento ptr_addrlen un puntatore ad intero in cui la
funzione metter la dimensione della struttura scritta.
113
funzione getpeername()
I socket TCP, una volta che la connessione TCP sia stata instaurata,
sono accedibili come se fossero dei file, mediante un descrittore di file
(un intero) ottenuto tramite una socket() o una accept() o una connect().
Con questo descrittore possibile effettuare letture tramite la funzione
read, che restituisce i byte letti dal flusso in entrata, e scritture tramite le
funzioni write e send, che spediscono i byte formando il flusso in uscita.
ssize_t read (int fd, void *buf, size_t count);
cerca di leggere count byte dal file descriptor fd, scrivendoli nel
buffer puntato da buf. Se count zero la read restituisce zero.
Se count maggiore di zero viene effettuata la lettura e viene
restituito il numero di byte letti (maggiore di zero, se tutto OK).
- Se viene restituito 0 (zero) significa end-of-file (fine stream),
ovvero significa che laltro end system ha volutamente chiuso la
connessione e quindi il socket non potr essere pi utilizzato per
leggere.
- Se viene restituito -1 accaduto un errore e viene settata la
variabile globale errno definita in <errno.h> con un valore che
indica quale errore avvenuto. In particolare, se errno vale EINTR
significa che il sistema operativo ha dovuto interrompere la system
call read, ma il socket non in stato di errore, quindi la read pu
essere ripetuta immediatamente con gli stessi parametri. Altro caso
particolare quando il socket stato definito non bloccante nel
qual caso se non ci sono byte disponibili viene restituito EAGAIN,
ed il socket rimane utilizzabile. Se invece errno ha un altro valore
(EBADF, EINVAL, EFAULT, ) il socket viene invalidato.
La funzione read, applicata ad un socket, presenta una particolarit. Pu
accadere che la read() restituisca meno byte di quanti richiesti, anche se
lo stream ancora aperto. Ci accade se il buffer a disposizione del
socket nel kernel stato esaurito. Sar necessario ripetere la read
(richiedendo il numero dei byte mancanti) fino ad ottenerli tutti. Oss.:
ssize_t definito in <unistd.h> ed un long.
I/O su Socket TCP: read()
101a
I/O su Socket TCP: write() (1)
101b
ssize_t write (int fd, const void *buf, size_t count);
cerca di scrivere fino a count byte nel buffer di sistema
corrispondente al file descriptor fd perch siano poi trasmessi. I
byte vengono letti dal buffer puntato da buf.
- Se count zero la write restituisce zero e non scrive nulla.
- Se count maggiore di zero viene effettuata la scrittura e viene
restituito il numero di byte scritti.
- Se viene restituito -1 accaduto un errore e viene settata la
variabile errno con un valore che indica lerrore.
- Se il socket configurato in modalit bloccante ( il default) la
write bloccante, cio attende fino a che tutti i byte sono stati
passati al buffer di sistema. Ci significa che se non c abbastanza
spazio nel buffer di sistema la write attende fino a che non sono
stati spediti abbastanza byte da permettere la scrittura di tutti i byte
passati. Durante questa attesa pu capitare che al processo arrivi un
segnale (es SIGUSR1) che deve essere gestito dal processo stesso;
in tal caso la write termina restituendo il numero di byte scritti
sul buffer di sistema. Se invece nessun byte stato ancora scritto
viene restituito -1 e indicato lerrore EINTR.
- Se invece il socket configurato in modalit non bloccante la
write scrive sul buffer di sistema il maggior numero di byte
possibile senza produrre attesa e poi termina restituendo il numero
di byte scritti. Se non stato possibile scrivere nulla la write
restituisce -1 senza attendere e setta errno al valore EAGAIN.
Altri possibili errori sono EBADF (file descriptor non valido),
EINVAL (file descriptor non permette scritture), EFAULT (il
buffer buf fuori dallo spazio di memoria permesso),
EPIPE (il socket stato chiuso dallaltro end system).
Indipendentemente da come i socket sono stati settati, nel momento in
cui viene invocata la write pu capitare che il processo venga
terminato dallarrivo di un segnale SIGPIPE che viene generato dalla
write stessa per indicare che il socket che si sta usando stato chiuso in
modo anormale dallaltro end system (inviando un segmento col flag
reset) o che non pi utilizzabile.
Per impedire la terminazione del processo ho due diverse possibilit:
1) istruire il processo per far intercettare i segnali SIGPIPE, nel qual
caso la write invece di inviare il segnale restituir -1 indicando come
errore EPIPE.
// da eseguire solo una volta, in fase di setup del processo
if( signal(SIGPIPE, SIG_IGN) == SIG_ERR )
{perror("signal SIGPIPE failed: ");exit(1);}
..
// poi si possono fare tutte le chiamate alla write
ris=write(socketfd, buff, n);
if(ris<0){
if(errno==EPIPE) { printf(chiusura anomala\n);exit(1); }

}
Cos per intercetto tutti i segnale SIGPIPE indipendentemente da quale
socket (usato dal processo) lo provoca.
2) utilizzare al posto della write la system call send, in cui pu essere
specificato di non generare il segnale SIGPIPE ma di restituire -1
indicando come errore EPIPE.
In questo modo, solo il segnale SIGPIPE di quella particolare
invocazione viene intercettato.
I/O su Socket TCP: write() (2)
101c
I/O su Socket TCP: send() (3)
101d
int send (int fd, const void *buf, size_t count, int flags);
cerca di scrivere fino a count byte nel buffer di sistema
corrispondente al file descriptor fd perch siano poi trasmessi.
I byte vengono letti dal buffer puntato da buf.
- Se count zero la send restituisce zero e non
scrive nulla.
- Se count maggiore di zero viene effettuata
la scrittura e viene
restituito il numero di byte scritti.
- Se viene restituito -1 accaduto un errore e
viene settata la
variabile errno con un valore che indica
lerrore.
Il comportamento viene influenzato dal valore del parametro flags,
il cui valore pu essere 0 oppure viene assegnato mediante OR bit a
bit delle seguenti costanti: MSG_OOB, MSG_DONTWAIT,
MSG_NOSIGNAL.
Se il valore di flags zero la send si comporta come la write.
Se viene specificato MSG_DONTWAIT la send non si blocca
bens scrive il numero di byte possibili nel buffer di sistema e
termina restituendo il numero di byte scritti, eventualmente zero.
Se viene specificato MSG_NOSIGNAL la send non solleva
leccezione di tipo SIGPIPE e quindi non rischia di far terminare il
processo. Al contrario, in caso di chiusura anormale della
connessione, restituisce -1 e setta la variabile errno al valore
EPIPE.
I/O su Socket TCP: (2)
TCP Output
102
Ogni socket TCP possiede un buffer per loutput (send buffer) in cui
vengono collocati temporaneamente i dati che dovranno essere trasmessi
mediante la connessione instaurata. La dimensione di questo buffer pu
essere configurata mediante unopzione SO_SNDBUF.
Quando unapplicazione chiama write() per n bite sul socket TCP, il
kernel cerca di copiare n byte dal buffer dellappl. al buffer del socket.
Se il buffer del socket e pi piccolo di n byte, oppure gi parzialmente
occupato da dati non ancora trasmessi e non c spazio sufficiente,
verranno copiati solo nc<n byte, e verr restituito dalla write il numero
nc di byte copiati.
Se il socket ha le impostazioni di default, cio di tipo bloccante, la fine
della routine write ci dice che sono stati scritti sul buffer del socket
quegli nc byte, e possiamo quindi riutilizzare le prime nc posizioni del
buffer dellapplicazione. Ci non significa affatto che gi i dati siano
stati trasmessi allaltro end-system.
Per attendere di ricevere almeno un byte, o leggere i byte gi arrivati, si
usa la gi descritta
ssize_t read (int fd, void *buf, size_t n);
Per attendere di ricevere TUTTI i byte richiesti, si implementa la
seguente funzione readn, che
-restituisce -1 in caso di errore, e setta errno
-restituisce il numero di byte letti se laltro end system chiude la
connessione
- restituisce il numero di byte chieste (e letti) se tutto ok.
ssize_t readn (int fd, char *buf, size_t n)
{
size_t nleft; ssize_t nread;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, buf+n-nleft, nleft)) < 0) {
if (errno != EINTR)
return(-1); // restituisco errore
}
else if (nread == 0) {
// EOF, connessione chiusa, termino
// esce e restituisco il numero di byte letti
break;
}
else // continuo a leggere
nleft -= nread;
}
return(n - nleft); // return >= 0
}
I/O su Socket TCP: utility (1)
103a
I/O su Socket TCP: utility (2)
Per attendere di consegnare al buffer di sistema TUTTI i byte richiesti
restituisce -1 in caso di errore e setta errno
restituisce il numero di byte da inviare ed inviati, se tutto OK.
ssize_t writen (int fd, const char *buf, size_t n)
{
size_t nleft; ssize_t nwritten; char *ptr;
ptr = buf; nleft = n;
while (nleft > 0)
{
if ( (nwritten = send(fd, ptr, nleft, MSG_NOSIGNAL )) < 0) {
if (errno == EINTR) nwritten = 0; /* and call write() again*/
else return(-1); /* error */
}
nleft -= nwritten; ptr += nwritten;
}
return(n);
}
Per consegnare da zero ad n byte da trasmettere, ma senza attendere:
restituisce -1 in caso di errore, se no restituisce il numero di byte scritti
ssize_t write_nowait (int fd, const char *buf, size_t n)
{
int nwritten;
do {
nwritten=send ( fd, buf, n, MSG_DONTWAIT|MSG_NOSIGNAL);
}while( (nwritten<0) && (errno==EINTR) );
return(nwritten);
}
103b
Per primo viene fatto partire il server, poi viene fatto partire il client che
chiede la connessione al server e la connessione viene instaurata.
Nellesempio (ma non obbligatorio) il client spedisce una richiesta al
server, questo risponde trasmettendo alcuni dati. Questa trasmissione
bidirezionale continua fino a che uno dei due (il client nellesempio)
decide di interrompere la connessione,
e tramite la close() chiude la
connessione. Infine il server
chiude a sua volta la connessione.
Interazioni tra Client e Server TCP
104
ephemeral
port
La funzione fork usata per duplicare un processo.
#include <unistd.h>
pid_t fork (void);
restituisce -1 in caso di errore. Se tutto va a buon fine restituisce 0
nel processo figlio ed un valore maggiore di zero (il pid process
identifier) nel processo padre.
Questa funzione viene chiamata nel processo (padre=parent), e
restituisce il risultato in due diversi processi (padre e figlio).
Se il figlio vuole conoscere il pid del padre user la funzione getppid().
I descrittori di file e di socket aperti dal padre prima della fork
sono condivisi col figlio, e possono perci essere usati da entrambi
per lI/O.
Inoltre, per come funziona la funzione close(), possibile per uno dei
processi (padre o figlio) chiudere una connessione aperta condivisa
(dai due processi) senza con questo impedire allaltro processo di
continuare ad utilizzare la connessione.
La fork viene usata per generare delle repliche del processo server, per
gestire in parallelo le connessioni che via via vengono instaurate.
funzione fork()
117
Un server banale in attesa su una porta TCP serializza le varie richieste
di apertura di una connessione dei client permettendo la connessione ad
un solo client per volta.
Server TCP pi evoluti invece, come i web server, una volta risvegliati
dalla richiesta di una connessione da parte di un client, effettuano una
fork() duplicando se stessi (il processo). Il processo figlio viene dedicato
a servire la connessione appena instaurata, il processo padre attende
nuove richieste di connessione sulla stessa porta.
A livello di interfaccia socket, questa situazione si ottiene cos:
Il server chiama la accept passando come argomento il socket
listening (socket in ascolto), e subito dopo chiama la fork.
il processo padre chiude il connected socket, e ripete la accept sul
listening socket, in attesa della prossima richiesta di connessione.
Invece il descrittore del connected socket (socket connesso) restituito
dalla accept resta aperto per il figlio, e viene utilizzato da questo
utilizzato per gestire lI/O con la connessione. Quando infine il figlio
termina il suo lavoro e chiude il connected socket con la close(), la
connessione viene finalmente terminata con la sequenza di FIN.
pid_t pid; int listenfd, connfd;
listenfd = socket (AF_INET, SOCK_STREAM, 0);
bind ( listenfd, (struct sockaddr*) &Local, sizeof(Local));
listen(listenfd, 10 );
for( ; ; ) {
connfd = accept ( listenfd, (struct sockaddr*) &Cli, &len);
pid = fork();
if ( pid !=0) close(connfd); /* processo padre */
else { /* processo figlio */
close(listenfd);
usa_nuova_connessione_indicata_da_newsockfd(connfd);
close(connfd); exit(0);
}
}
Server TCP Concorrenti (1)
118
Vediamo graficamente cosa capita a livello di TCP e di porte.
Entriamo un p nei dettagli del programma appena visto, per quanto
riguarda la scelta delle porte.
Consideriamo la situazione pi complicata, quella di unapplicazione
server collocata su un host con pi interfacce di rete, che vuole
permettere le connessioni su una certa porta convenzionale (la 6001)
da parte di client che accedono a una qualsiasi delle due interfacce
del server.
listenfd = socket (AF_INET, SOCK_STREAM, 0);
/* collega il socket ad un indirizzo IP locale e una porta TCP locale */
memset ( &Local, 0, sizeof(Local) );
Local.sin_family = AF_INET;
Local.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */
Local.sin_port = htons(6001);
bind ( listenfd, (struct sockaddr*) &Local, sizeof(Local));
/* accetta max 100 richieste simultanee di inizio conness., da adesso */
listen(listenfd, 100 );
/* accetta la prima conness. creando un nuovo socket per la conness. */
for( ; ; ){
connfd = accept(listenfd, (struct sockaddr*) &Cli, &len);
pid = fork();
if ( pid !=0 ) /* processo padre */
close ( connfd );
else { /* processo figlio */
close ( listenfd ); /* chiuso il listening socket */
il figlio usa il connected socket ()
close ( connfd );
exit(0);
}
}
119
Server TCP Concorrenti (2)
120
La quaterna (IP locale, Port Number locale , IP remoto, Port Number remoto)
che identifica univocamente una connessione TCP viene di solito
chiamata socket pair.
SERVER CLIENT
IP = IP_A1 IP = IP_B
IP = IP_A2 port = 2222
Server TCP Concorrenti (3)
listening socket
( *, 6001 , * , * )
connected socket
( IP_A2, 6001 , IP_B , 2222 )
IP_A2
IP_A1
listening socket
( *, 6001 , * , * )
IP_A1
IP_A2
dopo la listen(), prima della accept()
dopo la accept() , prima della fork()
121
Server TCP
Concorrenti
(4)
listening socket
( *, 6001 , * , * )
connected socket
( IP_A2, 6001 , IP_B , 2222 )
IP_A2
IP_A1
listening socket
( *, 6001 , * , * )
IP_A1
IP_A2
dopo la fork()
dopo la close(connfd) del padre, e la close(listenfd) del figlio
connected socket
( IP_A2, 6001 , IP_B , 2222 )
padre
figlio
padre
figlio
Unapplicazione di rete pu avere la necessit di accedere
contemporaneamente a pi tipi di input e di output, ad es. input di tipo
streamdalla tastiera, input di tipo streamda rete eventualmente da pi
connessioni contemporaneamente, input di tipo datagramda rete
anchesso eventualmente da pi socket contemporaneamente.
Esistono vari modelli di I/O disponibili in ambiente Unix:
I/O Bloccante
I/O Non Bloccante
I/O tramite Multiplexing
I/O guidato da signal
I/O asincrono (per ora poco implementato)
Consideriamo per ora il modello di I/O standard, per cui quando viene
effettuata una richiesta di I/O mediante una chiamata ad una primitiva di
tipo read() o write(), la primitiva non restituisce il controllo al chiamante
fino a che loperazione di I/O non stata effettuata, ovvero o la read() ha
letto da un buffer del kernel dei dati, o la write() ha scritto dei dati
dellutente in un buffer del kernel.
Le funzioni di I/O finora analizzate sono state descritte nel loro
funzionamento proprio secondo la modalit standard (bloccante).
Il problema che, quando lapplicazione effettua una read su un certo
descrittore di file o di socket, se i dati non sono gi presenti nella coda
del kernel dedicata a quel descrittore, lapplicazione rimane bloccata
fino a che i dati non sono disponibili, ed impossibile leggere dati
eventualmente gi pronti sugli altri descrittori di file o socket.
Analogamente per la write() se i buffer del kernel in cui si deve scrivere
il dato gi occupato.
Un problema analogo, caratteristico dei socket, si ha quando
lapplicazione effettua una chiamata alla funzione accept(), che
restituisce il controllo solo quando una richiesta di inizio connessione
disponibile (o meglio gi stata soddisfatta ed nella coda delle
connessioni stabilite).
I/O Multiplexing
122
Quello che serve un modo di ordinare al kernek di avvertirci quando,
in un insieme di canali di I/O, si verifica una condizione di
disponibilit allI/O, che pu essere cos definita:
1) o dei dati sono pronti alla lettura in una coda del kernel, e si pu
accedere mediante una read che restituir immediatamente il controllo al
chiamante con i dati letti,
2) o una coda di output del kernel si svuotata ed pronta ad accettare
dati in scrittura mediante una write,
3) o si verificato un errore in uno dei dispositivi di I/O e quindi una
read() o write() restituirebbe il valore -1,
4) o quando un socket listening disponibile a fornire immediatamente
un connected socket in risposta ad una chiamata di tipo accept(), perch
ha ricevuto una richiesta di connessione da un client,
Posix.1g mette a disposizione una primitiva, detta select(), che:
1) permette di effettuare attesa contemporaneamente su pi tipi di canali
di I/O in modo da essere risvegliati quando uno di questi canali
disponibile allI/O in lettura o scrittura o ha verificato un errore, o
ancora nel caso dei socket quando sono disponibili i cosiddetti dati fuori
banda (usati solo in casi particolarissimi perch meno utili di quanto il
nome farebbe presupporre),
2) e permette di fissare un limite allattesa, in modo da essere risvegliati
se non accade nulla allo scadere di un certo tempio limite. Questultima
possibilit pu collassare in unattesa di durata nulla, ovvero permette di
non effettuare attesa alcuna, ma solo di controllare lo stato istantaneo
dei vari canali e restituire subito il controllo al chiamante.
I/O Multiplexing
123
124
La funzione select permette di chiedere al kernel informazioni sullo
stato di descrittori di tutti i tipi, riguardo a loro disponibilit in lettura
scrittura o condizioni eccezionali, e di specificare quanto tempo al
massimo aspettare.
#include <sys/select.h>
int select ( int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, const struct timeval *timeout);
La funzione restituisce -1 in caso di errore,
0 se il timeout fissato scaduto,
altrimenti restituisce il numero di descrittori che hanno raggiunto la
condizione di disponibilit loro richiesta.
Lultimo argomento timeout dice al kernel quanto aspettare al massimo,
ed una struttura cos fatta:
struct timeval {
long tv_sec; /* secondi */
long tv_usec; /* microsecondi */
}
con questa struttura noi possiamo specificare alla select:
attesa infinita: attesa fino a che una delle condizioni si verificata. Si
passa un puntatore timeout nullo.
attesa limitata: attesa il numero di secondi e microsecondi specificati
nella struttura puntata dal puntatore timeout passato. In caso di timeout
la select restituisce 0.
attesa nulla: ritorna subito al chiamante dopo avere fotografato la
situazione dei descrittori. SI specifica settando a zero tv_sec e tv_usec.
NB: la timeval specifica microsecondi, ma i kernel non riescono a
discriminare solitamente sotto i 10 msec.
funzione select()
125
int select ( int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, const struct timeval *timeout);
I tre argomenti centrali di tipo fd_set*, readset writeset exceptset
specificano i descrittori che si vuole controllare rispetivamente per
verificare disponibilit alla lettura scrittura o eccezioni (out of band data
only).
Il tipo fd_set (descriptor set) un array di interi, in cui ogni bit
corrisponde ad un descrittore. Se il bit settato il descrittore viene
considerato appartenente al set, altrimenti non vi appartiene.
Esistono delle macro per settare o resettare gli fd_set.
void FD_ZERO (fd_set *fdset); clear di tutti i bit di fd_set
void FD_SET ( int fd, fd_set *fdset); setta il bit fd in fd_set
void FD_CLR ( int fd, fd_set *fdset); clear del bit fd in fd_set
int FD_ISSET ( int fd, fd_set *fdset); !=0 se il bit fd settato in fd_set
0 se il bit fd non settato
Con queste macro posso settare pulire e controllare lappartenenza o
meno di un descrittore allinsieme. Es.:
fd_set readset; dichiaro la variabile fd_set
FD_ZERO ( &readset ); inizializzo, azzero tutto,
insieme vuoto
FD_SET ( 1, &readset ); 1 appartiene allinsieme
FD_SET ( 4, &readset ); 4
FD_SET ( 7, &readset );
FD_ISSET ( 4, &readset ) restituisce != 0
FD_ISSET ( 3, &readset ) restituisce 0
Ricordarsi di inizializzare il set (FD_ZERO) altrimenti risultati
impredicibili.
funzione select() (2)
int select ( int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, const struct timeval *timeout);
Il primo argomento maxfdp1, specifica quali descrittori controllare, nel
senso che deve avere il valore pi alto tra i descrittori settati + 1.
Es.: se i descrittori settati sono 1, 4 , 7 maxfdp1 deve essere 8 = 7+1
I 3 descrittori di set passati per argomento contengono quindi i
descrittori da controllare, e vengono passati per puntatore perch la
select li modifica scrivendoci sopra il risultato.
Quando la select termina si controllano ciascuno dei 3 fd_set, chiedendo
tramite la macro FD_ISSET() quali descrittori sono settati.
Se un descrittore (es. 4) non settato (es. FD_ISSET(4, &readset )== 0)
significa che non pronto.
Se invece il descrittore settato (es. FD_ISSET(4, &readset ) != 0)
significa che pronto.
Il valore restituito dalla select dice quanti descrittori sono stati
settati.
se la select restituisce 0 significa che scaduto il timeout.
se la select restituisce -1 ce stato un errore o avvenuta una
signal.
N.B. esiste una define che specifica la costante FD_SETSIZE ovvero il
numero di descrittori che pu contenere la struttura fd_set.
Vediamo ora un esempio di uso della select, con cui implementiamo un
web server, che lavora in parallelo senza dover fare delle fork().
126
funzione select() (3)
Prima parte del server, inizializzazione:
typedef SA struct sockaddr ;
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client [FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char line[MAXLINE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
127
esempio duso della select()
server che non utilizza la fork() (1)
for ( ; ; ) {
rset = allset; /* structure assignment */
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if ( FD_ISSET( listenfd, &rset) ) { /* new client connection */
clilen = sizeof(cliaddr);
connfd = accept( listenfd, (SA *) &cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE) err_quit("too many clients");
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd) maxfd = connfd; /* for select */
if (i > maxi) maxi = i; /* max index in client[] array */
if (--nready <= 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ( (n = Readline(sockfd, line, MAXLINE)) == 0) {
/*connection closed by client */
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
} else
writen(sockfd, line, n);
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
}
128
server che non utilizza la fork() (1)
Advanced TCP Socket
130
Le opzioni per i socket sono controllate mediante tre tipi di primitive:
1) le funzioni getsockopt() e setsockopt(), che permettono di
configurare alcune caratteristiche proprie solo dei socket, quali
dimensioni dei segmenti, controlli sulla funzionalit della connessione,
modalita di utilizzo degli indirizzi;
2) la funzione fcntl(), che invece consente di settare caratteristiche
comuni a tutti i descrittori di I/O, quali comportamento bloccante o
non bloccante e I/O guidato dai signal.
3) la funzione ioctl(), che ripete operazioni delle fcntl ed inoltre
effettua operazioni riguardanti ARP e routing.
Le opzioni tipiche per i socket possono essere settate solo quando il
socket reso disponibile allinterfaccia di programmazione.
Consideriamo ad es. il caso di un connected socket ottenuto da un
server in risposta ad una chiamata alla accept() a partire da un socket
listening. Il connected socket viene creato dopo la listen() quando arriva
una richiesta di connessione dal client, e tutto il procedimento di
instaurazione della connessione avviene senza che il programmatore
possa intervenire, in quanto il socket creato verr reso disponibile al
programmatore solo quando questo far eseguire la accept().
Per rendere possibile configurare il socket anche in questa situazione
temporanea, linterfaccia socket implementa la politica seguente: il
connected socket eredita dal listening socket alcune opzioni, invece
di assumere le opzioni di default. Queste opzioni sono:
SO_DEBUG, SO_DONTROUTE, SO_KEEPALIVE, SO_LINGER,
SO_OOBINLINE, SO_RCVBUF e SO_SNDBUF. In tal modo se
vogliamo che il connected socket abbia queste opzioni gia durante la
fase del thee-way-handshake dobbiamo settare in quel modo il listening
socket.
In http://www.cs.unibo.it/~ghini/didattica/sistemi3/SOCKOPTS/checkopts.c
e implementato un esempio di lettura delle opzioni di default di un socket.
Le Opzioni per i Socket
Il formato di queste due funzioni il seguente:
#include <sys/socket.h>
int getsockopt ( int sockfd, int level, int optname,
void *optval, socklen_t *optlen );
int setsockopt ( int sockfd, int level, int optname,
const void *optval, socklen_t optlen );
restituiscono 0 se tutto OK, -1 in caso di errore.
- Il primo argomento socketfd un descrittore di socket aperto con una
socket(), su cui operano le funzioni.
- Largomento level indica a che livello di protocollo deve agire
lopzione: a livello di socket generale (level=SOL_SOCKET), a livello
IPv4(IPPROTO_IP), IPv6(IPPROTO_IPV6), ICMPv6
(IPPROTO_ICMPV6), a livello TCP (level=IPPROTO_TCP).
- optname specifica lopzione da leggere /settare.
- optval un puntatore ad una variabile di tipo dipendente dallopzione
specificata, che contiene il valore nuovo da settare dellopzione da
configurare (caso setsockopt) o che conterr il valore attuale
dellopzione (caso getsockopt).
- optlen contiene la dimensione della variabile puntata da optval.
Le opzioni possono effettuare due diverse operazioni:
- settare o resettare un flag,
- assegnare o leggere un valore pi complesso.
Nel caso dei flags, il valore restituito o passato (optval) punta ad un
intero, che vale zero se lopzione e disabilitata, vale nonzero se
lopzione e abilitata.
Nel caso non flags optval punta ad un dato di tipo diverso, come
indicato nella seguente tabella:
131
funzioni getsockopt() e setsockopt()
T
a
b
e
l
l
a

d
e
l
l
e

O
p
z
i
o
n
i

S
o
c
k
e
t
G
e
n
e
r
i
c
h
e
,

c
i
o


d
i

l
i
v
e
l
l
o

S
o
c
k
e
t
,

p
e
r

g
e
t
s
o
c
k
o
p
t
(
)

e

s
e
t
s
o
c
k
o
p
t
(
)
1
3
2
P
e
r

q
u
e
s
t
e

o
p
z
i
o
n
i
,

n
e
l
l
e

f
u
n
z
i
o
n
i

g
e
t
s
o
c
k
o
p
t
(
)

e

s
e
t
s
o
c
k
o
p
t
(
)


d
e
v
e

e
s
s
r
e
u
t
i
l
i
z
z
a
t
o

c
o
m
e

s
e
c
o
n
d
o

a
r
g
o
m
e
n
t
o

l
e
v
e
l
=
S
O
L
_
S
O
C
K
E
T
.
Consideriamo le principali opzioni caratteristiche di tutti i socket,
quelle identificate dal livello SOL_SOCKET.
SO_BROADCASTquesta opzione abilita o disabilita la possibilit
per un socket di spedire messaggi broadcast. Viene applicato solo ai
socket datagram(DGRAM) e solo se la rete sottostante lo permette (es:
ethernet, non punto a punto). Per default questa opzione
disabilitata, per impedire ad un processo di spedire accidentalmente
un datagramin broadcast, ad es. se lindirizzo IP di destinazione viene
preso a linea di comando e si digita per errore un indirizzo di
broadcast. In tal caso il kernel si accorge di avere a che fare con un
datagramdi broadcast il cui invio disabilitato, e restituisce un errore
di tipo EACCES.
SO_DEBUG questa opzione supportata solo da TCP, e ordina al
kernel di mantenere informazioni su tutti i pacchetti spediti o ricevuti
da/a un certo socket, in una coda circolare. Il programma trcp
esaminera questa coda.
SO_DONTROUTE questa opzione e applicata per bypassare il
normale meccanismo di routing dei pacchetti in uscita, ad es: per farli
uscire da uninterfaccia di rete diversa da quella prevista dalle
tabelle interne di routing. Viene usata ad es. dai processi daemon del
routing (routed o gated) per instradare un pacchetto sullinterfaccia
giusta quando le tabelle di routing sono sbagliate.
SO_KEEPALIVE questa opzione applicata solo agli streamTCP,
per verificare se una connessione che da molto tempo non scambia
dati debba essere chiusa o no. Il motivo per cui una connessione
deve essere chiusa da un end systeme che laltro end systema) e
down, b) non e raggiungibile (rete partizionata o problema nel
routing), c) non e piu interessato a quella connessione.
Opzioni Socket Generiche (1)
133
SO_KEEPALIVE (continuazione) Quando un socket TCP ha questa
opzione settata, se nessun dato viene scambiato in una delle due
direzioni della connessione per 2 ore, il TCP spedisce un segmento,
detto keepalive probe, allaltro end-system, per verificarne la
situazione, e si aspetta di ricevere un ACK.
1) se il peer risponde con un ACK tutto e OK, ed il TCP mandera un
nuovo probe dopo altre due ore di inattivita.
2) se il peer risponde con un segmento RST (reset), significa che e
andato in crash e poi ha effettuato il reboot. Il socket allora viene
chiuso, ed la variabile derrore del socket settata a ECONNRESET.
3) se non ce risposta dal peer, il TCP riprova a mandare altri 8
segmenti keepalive probe, ogni 75 secondi, aspettando risposta.
3.1) Se non viene ricevuta alcuna risposta il socket e chiuso e la var.
derrore settata a ETIMEOUT.
3.2) se invece viene ricevuta un ICMP error in risposta ad uno dei
keepalive probe, il socket viene chiuso, e viene restituito lerrore
indicato dallICMP, che sara di tipo EHOSTUNREACH, ovvero
lhost non e raggiungibile.
La specifica Posix.1g stabilisce anche le modalita per settare
lintervallo di attesa (le 2 ore) ad un valore diverso, ma tale opzione e
implementata raramente.
Questa Opzione SO_KEEPALIVE serve a stabilire se il peer host e
andato in crash. Invece il crash dellapplicazione peer viene
individuato e notificato dal TCP peer. Cioe quando nellaltro end
systemil processo che gestiva il socket va in crash, il TCP di
quellhost spedisce un segmento FIN per chiudere la connessione, e
questa chiusura pu essere individuata con una read() o una
select() settata per verificare la possibilita di leggere da quel
socket. Non esiste altro modo di accorgersi di un crash se non
cercando di fare un test per lettura.
Opzioni Socket Generiche (2)
134
SO_RCVBUF e SO_SNDBUF Queste due opzioni servono a
modificare la dimensione dei buffer di ricezione e trasmissione del
TCP e dellUDP.
Per il TCP la dimensione del buffer di ricezione viene mandata allatto
dellinstaurazione della connessione. E quindi necessario che per il
server questa opzione sia settata prima della chiamata alla listen(),
mentre per il client deve essere settata prima della chiamata alla
connect().
Invece per UDP il buffer di ricezione determina la dimensione
massima dei datagramche possono essere accettati.
SO_REUSEADDR e SO_REUSEPORTQueste due opzioni servono
a permettere di effettuare la bind() su porte e indirizzi IP gia utilizzati
da qualche altro processo. La SO_REUSEADDR ad es. puo essere
utile nei seguenti casi:
a) si cerca di fare la bind per un listening socket che e stato chiuso e si
vuol fare ripartire, quando ancora esiste un connected socket nato dal
listening socket appena chiuso.
b) ci sono piu connected socket che lavorano sulla stessa porta di un
host ma con IP diversi. E il caso dei web server che devono lavorare
sulla stessa well know port 80 ma su interfacce diverse.
SO_TYPE Questa opzione puo essere usata solo in lettura, e
restituisce il tipo del socket, SOCK_STREAM o SOCK_DGRAM.
Opzioni Socket Generiche (3)
135
SO_LINGERQuesta opzione determina le modalita di chiusura
realizzate dalla funzione close(). Viene usato come argomento optval
della setsockopt() un puntatore ad una struttura di tipo:
struct linger { int l_onoff; /* 0=off , nonzero=on */
int l_linger; /* linger time, Posix.1g vuole secondi */
}
Per default la close() restituisce subito il controllo al chiamante, ma se
alcuni dati rimangono nei buffer di spedizione il TCP tenta di spedirli.
1) se l_onoff==0 lopzione SO_LINGER e disabilitata, quindi viene
settato il modo di default appena visto.
In questo modo non sappiamo se il TCP peer ha ricevuto tutti i dati, e
a maggior ragione non sappiamo se lapplication peer li ha ricevuti.
2) se l_onoff != 0 e l_linger==0 quando un socket chiama la close(), il
TCP chiude la connessione in modo traumatico, non spedendo i dati
eventualmente bufferizzati per la spedizione, e mandando un segment
RST (reset) allaltro end-system. Non si va nello stato TIME_WAIT e
si rischia di danneggiare lapertura di una nuova connessione con gli
stessi indirizzi IP e di porta.
Anche in questo caso non sappiamo se il TCP peer ha ricevuto
tutti i dati, e nemmeno se li ha ricevuti l application peer.
Opzioni Socket Generiche (4)
136
SO_LINGER(continuazione)
3) se l_onoff != 0 e l_linger !=0 quando un socket chiama la close(),
se il socket e di tipo bloccante (e il default) il TCP tenta di spedire i
dati eventualmente bufferizzati per la spedizione, fino a che si verifica
una di queste condizioni:
3.1) tutti i dati sono trasmessi e riscontrati dal TCP peer, ed allora la
funzione close() restituisce il controllo al chiamante con risultato 0,
passando dallo stato TIME_WAIT.
Anche in questo caso per, anche se sappiamo che il TCP ha ricevuto i
dati non abbiamo garanzie che lapplication peer riceva i dati. Puo
capitare infatti che dopo che il TCP peer ha spedito lACK per i dati ed
il FIN, e quindi la close() e terminata, lapplication peer vada in crash
e non riesca a leggere dalla coda del TCP peer.
3.2) oppure scade il tempo assegnato di attesa l_linger e la funzione
close restituisce -1 mandando un segment RST (reset) allaltro
end-system, e non passa dallo stato TIME_WAIT.
Opzioni Socket Generiche (5)
137
La funzione shutdown() e utilizzata per chiudere una connessione in
modo differente rispetto alla close().Infatti:
- mentre la close() decrementa solo il contatore dei processi che
utilizzano quel socket e quando il contatore e zero spedisce il
segmento FYN, la shutdown spedisce subito il segmento di FIN
(anche se il contatore e maggiore di zero) ovviamente senza passare
avanti agli altri dati bufferizzati per la spedizione.
- mentre la close() chiude entrambe le direzioni della connessione, e
quindi impedisce di usare con quel socket sia primitive di input sia di
output (no read no write dopo close() ), la shutdown da la possibilita di
effettuare chiusure asimmetriche di una connessione, specificando quale
direzione deve essere interrotta.
int shutdown (int sockfd, int howto);
restituisce 0 se tutto OK, -1 in caso di errore.
Largomento socketfd un descrittore di socket.
Largomento howto specifica lazione che deve essere effettuata sul
socket sockfd, ed e una delle seguenti:
- SHUT_WR lapplicazione chiude il socket sia in scrittura che in
lettura,, senza badare al contatore di processi per quel socket. Tutti i dati
eventualmente presenti nelle code di output verranno spediti, e poi
verra spedito un SYN segment, per terminare il lato di output della
connessione. Rimane possibile effettuare delle read() fino a che laltro
end-systemnon effettua a suo volta un\a close() che fa inviare il SYN
segment verso chi aveva effettuato la chiamata alla shutdown(). Questo
tipo di chiusura viene detta half-close.
- SHUT_RD lapplicazione chiude il socket in lettura, resta possibile
effettuare le write(). Non piu possibile effettuare le letture, e tutti i
dati eventualmente gia ricevuti dal TCP e presenti nelle code per linput
vengono scartati. Vengono scartati anche eventuali dati giunti
dopo la shutdown(). 138
funzione shutdown() (1)
- SHUT_RDWR lapplicazione chiude il socket sia in scrittura che in
lettura, come se effettuasse due chiamate alla shutdown, con parametro
SHUT_RD e poi con parametro SHUT_WR.
vediamo qui una rappresentazione di una half close (SHUT_WR).
139
funzione shutdown() (2)
Garanzie di
Trasmissione Completata (1)
140
Garanzia per il Client che il Server ha ricevuto tutti i dati.
Un modo sicuro per sapere se lapplicazione dellaltro end system(non
solo il TCP) ha ricevuto i dati sostituire la chiamata alla close() con
una chiamata alla shutdown() usando come secondo argomento la
costante SHUT_WR, e procedere poi con una chiamata alla read().
In questo modo la shutdown manda il segmento di FIN, ma lascia
aperto il socket in lettura, permettendo di effettuare la chiamata alla
read() che altrimenti restituirebbe immediatamente un errore. La read()
rimane bloccata fino a che lapplication peer termina la lettura di tutti i
dati e legge il FIN, quindi effettua la close() che manda il segmento
FIN di risposta.
La read() allora riceve lend-of-file e termina restituendo 0. Si ha
allora la garanzia che la applicazione peer ha ricevuto tutti i dati.
Garanzia per il Client che il Server ha ricevuto tutti i dati.
Un altro modo per garantire che lapplication peer ha ricevuto tutti i
dati e usare il cosiddetto application-level acknowledgment o
application ACK.
Il client dopo avere spedito tutti i suoi dati si blocca su una read
aggiuntiva, che rappresenta lattesa per un ACK a livello di
applicazione. Il server, dopo avere ricevuto tutti i dati effettua una
write di un byte, che rappresenta lACK a livello di applicazione.
Quando il client ritorna dalla read() effettua la close() che manda il
FIN segment. Solo allora lapplication peer effettua la close().
In questo modo si ha la garanzia che il processo server ha letto i dati
che gli sono stati inviati.
141
Garanzie di
Trasmissione Completata (2)
T
a
b
e
l
l
a

d
e
l
l
e

O
p
z
i
o
n
i

S
o
c
k
e
t
p
e
r

T
C
P
,

c
i
o


d
i

l
i
v
e
l
l
o

I
P
P
R
O
T
O
_
T
C
P
,

p
e
r

g
e
t
s
o
c
k
o
p
t
(
)

e

s
e
t
s
o
c
k
o
p
t
(
)
1
4
2
P
e
r

q
u
e
s
t
e

o
p
z
i
o
n
i
,

n
e
l
l
e

f
u
n
z
i
o
n
i

g
e
t
s
o
c
k
o
p
t
(
)

e

s
e
t
s
o
c
k
o
p
t
(
)


d
e
v
e

e
s
s
e
r
e

u
t
i
l
i
z
z
a
t
o

c
o
m
e

s
e
c
o
n
d
o

a
r
g
o
m
e
n
t
o

l
e
v
e
l
=
I
P
P
R
O
T
O
_
T
C
P
.
143
Opzioni Socket per TCP
Queste opzioni si usano specificando il livello IPPROTO_TCP.
TCP_KEEPALIVE Questa opzione specifica il tempo (in sec.) di
inattivita della connessione prima che venga fatto partire il segmento
di keepalive probe. Il valore di default e di 7200 sec. (2 ore). Questa
opzione e realmente attivata solo quando lopzione SO_KEEPALIVE
e abilitata.
TCP_MAXSEG Questa opzione restituisce o setta il maximum
segment size (MSS) per la connessione TCP.
TCP_NODELAY Per default il TCP abilita il cosiddetto Algoritmo di
Nagle (Nagle Algorithm) il cui scopo e di diminuire il numero di
segmenti piccoli trasmessi, come nel caso di client telnet che
prevedono lACK per ogni singolo carattere battuto a tastiera. Questo
algoritmo legato allalgoritmo dellACK ritardato (delayed ACK
algorithm) che fa aspettare il TCP per circa 50-200 msec) prima di dare
lack ad un segmento, sperando di poter accodare lACK ad un
segmento di dati.
Questi due algoritmi assieme cercano di minimizzare il numero di
segmenti trasmessi, ma producono ritardo per applicazioni che
scambiano piccoli dati e quasi solo in una direzione.
Lopzione TCP_NODELAY disabilita luso di questi algoritmi.
Nagle algorithmDISABLED
Nagle algorithm Enabled settata TCP_NODELAY opt.
Consente di inviare uno stesso datagram UDP a piu destinatari, i quali
devono essersi preventivamente registrati come membri del gruppo di
multicast caratterizzato da un certo indirizzo di multicast.
Indirizzi di multicast:
Classe D, 224.0.0.0 - 239.255.255.255
Indirizzi di Multicast Speciali:
224.0.0.1 (all-host group) vi si devono registrare tutti gli host di
una sottorete, che implementano il multicast.
224.0.0.2 (all-router group) vi si devono registrare tutti gli host di
una sottorete, che implementano il multicast.
Operazioni necessarie per ricevere datagram UDP via multicast:
creazione di un socket UDP
collegamento ad una porta del protocollo UDP (bind)
join ad un indirizzo di multicast (setsockopt).
Operazioni necessarie per smettere di ricevere via multicast:
leave del gruppo multicast (setsockopt).
N.B. Se con la bind non specifico un indirizzo IP, posso ricevere
datagram UDP sia originati da multicast che da unicast, per la
porta UDP specificata.
N.B. Se con la bind specifico lindirizzo IP di multicast a cui faro il
join, potro ricevere solo datagram UDP di multicast per quello
indirizzo di multicast.
Operazioni opzionali per spedire datagram UDP via multicast:
Specificare il TTL dei datagram UDP multicast.
Se non si specifica, il default e 1, non si esce dalla subnet.
Specificare se il mittente deve ricevere copia del datagram(se fa
parte del gruppo di multicast.
144
Opzioni Socket per IP: Multicast (1)
indica se i datagram
di multicast spediti
devono andare anche
al mittente, se questo
appartiene
al gruppo
u_char IP_MULTICAST_LOOP
specifica il TTL dei
datagramdi
multicast da spedire
u_char IP_MULTICAST_TTL
indica linterfaccia
di rete da usare per
spedire i datagram di
multicast
struct in_addr IP_MULTICAST_IF
toglie il socket UDP
dal gruppo di
multicast
struct ip_mreq IP_DROP_MEMBERSHIP
collega il socket
UDP ad uno
specifico gruppo di
multicast
struct ip_mreq IP_ADDR_MEMBERSHIP
uso tipo di dato opzione
Opzioni di livello IPPROTO_IP
Le opzioni utilizzate per configurare un socket UDP per la
trasmissione/ricezione di datagram per un certo indirizzo di multicast,
vengono settate mediante la primitiva setsockoption, utilizzando il
livello IPPROTO_IP, ed i comandi e le strutture dati specificati in
tabella.
145
Opzioni per il Multicast in IPv4
146
esempio: receiver di datagram UDP
per gruppo di Multicast
struct ip_mreq Mreq;
.....
socketfd = socket (AF_INET, SOCK_DGRAM, 0);
OptVal = 1;
setsockopt (socketfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&OptVal, sizeof(OptVal) );
Local.sin_family = AF_INET;
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_port = htons( 6001); // local_port_number
bind ( socketfd, (struct sockaddr*) &Local, sizeof(Local));
/* join the multicast group. */
Mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
Mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(socketfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&Mreq, sizeof(Mreq) );
for (j=1;j<=1000;j++) {
Fromlen=sizeof(struct sockaddr);
msglen = recvfrom( socketfd, msg, (int)SIZEBUF, 0,
(struct sockaddr*)&From, &Fromlen);
sprintf(string_remote_ip_address,"%s",inet_ntoa(From.sin_addr);
remote_port_number = ntohs(From.sin_port);
printf("ricevuto msg: \"%s\" len %d, from host %s, port %d\n",
msg, msglen, string_remote_ip_address, remote_port_number);
}
147
esempio: sender di datagramUDP
per gruppo di Multicast
struct ip_mreq Mreq; int ttl, int loopback;
.....
socketfd = socket (AF_INET, SOCK_DGRAM, 0);
OptVal = 1;
/* set TTL to traverse up to multiple routers */
ttl = TTL_VALUE; // per default 1
setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&ttl, sizeof(ttl));
/* join the multicast group, NON NECESSARIO per SPEDIRE */
Mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
Mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(socketfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&Mreq, sizeof(Mreq) );
/* disable loopback , NON NECESSARIO se non si fa join */
loopback =0;
setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_LOOP,
(char *)&loopback, sizeof(loopback));
for (j=1;j<=1000;j++) {
To.sin_family = AF_INET;
To.sin_addr.s_addr = inet_addr("234.5.6.7" );
To.sin_port = htons( 6001 ); // remote_port_number
addr_size = sizeof(struct sockaddr_in);
/* send to the address */
sendto ( socketfd, msg, strlen(msg) , 0,
(struct sockaddr*)&To, addr_size);
}
La funzione fcntl significa file control e serve ad effettuare alcune
operazioni su vari descrittori non solo di socket ma in generale di file.
In particolare la funzione fcntl permette di:
configurare lI/O di un descrittore come non bloccante o bloccante
usando nella fcntl il comando F_SETFL con argomento
O_NONBLOCK (O_BLOCK),
configurare lI/O di un descrittore come guidato dai signal usando
nella fcntl il comando F_SETFL con argomento O_ASYNC, ottenendo
che in corrispondenza di ogni modifica della situazione del socket
venga scatenato un SIGIO signal.
settare un proprietario per il descrittore (comando F_SETOWN),
ovvero definire quale il processo che viene avvisato con il signal
SIGIO quando il descrittore e disponibile allI/O, ma questo solo se e
stato settato il socket come guidato dai signal. Si ricorda che un socket
appena creato con la socket() non ha proprietario, un connected socket
ha lo stesso proprietario del listenung socket
conoscere il proprietario corrente per il descrittore (F_GETOWN).
#include <fcntl.h>
int fcntl (int fd, int cmd, ... /* int arg */ );
restituisce -1 in caso di errore,
un altro valore dipendente dal comando in caso tutto OK.
Le proprieta di un descrittore di file (e di socket) sono definite
mediante alcuni flags, che la funzione fcntl permette di leggere (usando
come secondo argomento cmd=F_GETFL) e di settare (usando come
secondo argomento cmd=F_SETFL).
I due flags che ci interessano per i socket sono:
O_NONBLOCK non blocking I/O
O_ASYNC signal-driven I/O notification
148
Opzioni Socket tramite fcntl (1)
In generale la procedura corretta per settare un flags consiste nel
leggere i flags del descrittore mediante il comando F_GETFL,
modificare solo il flag che interessa con un OR logico, settare i nuovi
flags per il socket mediante il comando F_SERFL.
Nel seguente esempio viene settato il flag O_NONBLOCK, quindi
il socket diventa non bloccante.
Procedura corretta
int flags, sockfd;
sockfd = socket(....);
if ( (flags=fcntl(sockfd,F_GETFL,0)) <0 )
exit(1);
flags |= O_NONBLOCK;
if ( fcntl(sockfd,F_SETFL,flags) <0 )
exit(1);
Procedura errata, vengono azzerati tutti gli altri flags.
int sockfd;
sockfd = socket(....);
if ( fcntl(sockfd,F_SETFL, O_NONBLOCK )<0)
exit(1);
Infine in questo esempio viene resettato il flag O_NONBLOCK, quindi
il socket diventa bloccante.
int flags, sockfd;
sockfd = socket(....);
if ( (flags=fcntl(sockfd,F_GETFL,0)) <0 )
exit(1);
flags &= O_NONBLOCK;
if ( fcntl(sockfd,F_SETFL,flags) <0 )
exit(1);
149
Opzioni Socket tramite fcntl (2)
Se per un socket viene settato il flags O_ASYNC, quando il socket
diventa disponibile allI/O, o e in errore, viene lanciato un signal
SIGIO al processo proprietario del socket, o ai processi del gruppo
proprietario del socket, se il proprietario esiste.
Per settare il proprietario si usa la fcntl con secondo argomento
F_SETOWN passando come terzo parametro o il numero positivo pid
del processo proprietario, o il numero negativo ottenuto cambiando di
segno il numero di gruppo.
Per conoscere il proprietario si usa la fcntl con secondo argomento
F_GETOWN. La funzione restituisce un intero positivo (il pid del
proprietario) o un numero negativo diverso da -1, che e lidentificatore
del gruppo cambiato di segno.
settare il proprietario di un socket
int sockfd,pid;
sockfd = socket(....);
if ( fcntl(sockfd,O_SETOWN, pid ) <0 )
exit();
settare il gruppo di un socket
int sockfd, gid;
sockfd = socket(....);
if ( fcntl(sockfd,O_SETOWN , -gid ) <0 )
exit();
150
Opzioni Socket tramite fcntl (3)
Per default un socket e bloccante. Cio significa che quando il socket
deve effettuare unoperazione di I/O, se questa non puo essere
terminata immediatamente il processo si mette in attesa aspettando la
fine delloperazione. Se invece, mediante la fcntl vista prima, il socket
viene settato Nonblocking il comportamento delle funzioni cambia:
Operazioni di input (read, recvfrom). Con un socket Non
Bloccante, se loperazione di input non puo essere terminata (cioe
non ce nemmeno un byte per il socket TCP o non ce nemmeno un
datagramper il socket UDP) la funzione ritorna immediatamente al
chiamante restituendo il codice derrore EWOULDBLOCK.
Operazioni di output (write, sendto ).
Con un socket Non Bloccante di tipo TCP, se loperazione di
scrittura non puo essere effettuata nemmeno in parte perche manca
spazio nei buffer del TCP in cui andare a scrivere i dati, la funzione
ritorna immediatamente al chiamante restituendo il codice derrore
EWOULDBLOCK. Se invece e rimasto spazio, viene effettuata una
scrittura di una porzione di dati minore o uguale alla dimensione del
buffer libero, e la write restituisce il numero di byte scritti.
Con un socket Non Bloccante di tipo UDP invece il problema non
sussiste perche nessun datagramviene mantenuto in un buffer perche
non ce ritrasmissione, quindi il datagram UDP viene immediatamente
spedito e vada come vada. Quindi una primitiva di output di un socket
UDP non blocca mai il processo che leffettua.
Operazioni di Accettazione Richiesta Connessione (accept).
Con un socket Non Bloccante, se loperazione di accept non puo
restituire immediatamente una nuova connessione perche la coda delle
connessioni accettate e vuota, la funzione ritorna immediatamente al
chiamante restituendo il codice derrore EWOULDBLOCK.
151
I/O Non Bloccante (1)
Operazioni di Richiesta Connessione (connect).
Con un socket UDP la funzione connect non e realmente bloccante,
perche deve solo scrivere nel kernel lindirizzo IP e il numero di porta
dellaltro end-system, quindi anche nel caso di socket Non Bloccante la
connect per lUDP effettua sempre loperazione interamente e
restituisce il controllo al chiamante.
Invece per il TCP la chiamata del client alla connect() di un socket
bloccante deve aspettare che, allinterno del three way handshake, il
client abbia ricevuto lACK per il SYN segment, sia stato ricevuto, e
quindi puo veramente bloccare il processo.
Se il socket TCP e di tipo Non Bloccante, la chiamata del client alla
connect() fa iniziare il procedimento di inizio connessione, cioe fa
spedire il primo SYN segment, ma se la connessione non puo
immediatamente essere instaurata la connect() termina con un codice
derrore EINPROGRESS ad indicare che loperazione continua a
livello inferiore.
Con una select() sara possibile accorgersi di quando il socket
impegnato nella richiesta di connessione ha stabilitpo la connessione, e
quindi puo essere ripetuta la connect().
Si noti che puo capitare che la connect() restituisca OK perche e
riuscita ad avere immediatamente risposta ed ha instaurato la
connessione richiesta.
152
I/O Non Bloccante (2)
socketfd = socket(AF_INET, SOCK_STREAM, 0);
/* SETTO IL SOCKET COME NON BLOCCANTE */
set_socket_non_blocking(socketfd); /* ora socket e' non bloccante */
... qui va messo il necessario per la bind .......
bind(socketfd, (struct sockaddr*) &Local, sizeof(Local));
memset ( &Serv, 0, sizeof(Serv) );
Serv.sin_family = AF_INET;
Serv.sin_addr.s_addr = inet_addr(string_remote_ip_address);
Serv.sin_port = htons(remote_port_number);
/* connection request, NON BLOCCANTE */
ris = connect(socketfd, (struct sockaddr*) &Serv, sizeof(Serv));
if (ris != SOCKET_ERROR) { /* connessione riuscita subito */
set_socket_blocking(socketfd); /* ora socket e' bloccante */
.....................
}
else { /* (ris == SOCKET_ERROR) */
if(errno!=EINPROGRESS) exit(1); /* conness. non terminata */
FD_ZERO(&fdr); FD_SET(socketfd,&fdr);
fdw=fdr;
.....................
ris=select(socketfd+1,&fdr,&fdw,NULL,NULL);
if ((FD_ISSET(socketfd,&fdr))||(FD_ISSET(socketfd,&fdw))) {
ris=connect(socketfd,(struct sockaddr*) &Serv, sizeof(Serv));
if (ris == SOCKET_ERROR) {
if(errno==EISCONN) {
printf ("connessione gia' esistente, OK\n");
set_socket_blocking(socketfd); /* socket e bloc*/
}
else exit(1); /* connessione NON riuscita */
}
}
}
153
Connect Non Bloccante (1)
/* SETTO IL SOCKET COME NON BLOCCANTE */
int set_non_blocking(int socketfd) {
int flags;
if ( (flags=fcntl(socketfd,F_GETFL,0)) <0 ) return(0); /* errore */
flags |= O_NONBLOCK;
if ( fcntl(socketfd,F_SETFL,flags) <0 ) return(0); /* errore */
return(1);
}
/* SETTO IL SOCKET COME BLOCCANTE */
int set_blocking(int socketfd) {
int flags;
if ( (flags=fcntl(socketfd,F_GETFL,0)) <0 ) return(0); /* errore */
flags &= (~O_NONBLOCK);
if ( fcntl(socketfd,F_SETFL,flags) <0 ) return(0); /* errore */
return(1);
}
N.B.
per lesempio completo vedere nella home page
154
Connect Non Bloccante (2)

Vous aimerez peut-être aussi