Cursul 7 - Protocolul UDP. Nivelul Transport

image-20240308190244288

Nivelul Rețea prezintă următoarele neajunsuri:

  • nu garantează transmiterea datelor
  • nu poate detecta erori de transmisie
  • nu păstrează ordinea de transmisie a pachetelor

Protocoalele de nivel Transport își propun remedierea acestor puncte slabe: implementarea lor individualizează procesele locale și ramifică transmisia informației de la host la host prin introducerea porturilor.

Fiecare proces poate fi identificat printr-un port unic, asociat socket-ului deschis de către acesta din urmă. Astfel, este soluționată problema partajării concurente a resurselor de rețea (un proces nu așteaptă încheierea comunicației inițiate de către alte procese).

Obs: ID-ul unui port este reprezentat pe 2 octeți. Totodată, există porturi rezervate anumitor protocoale și servicii de sistem (ID-uri alocate între 0-1024).


Protocolul UDP

  • cel mai simplu protocol de transport

  • oferă light-checking pentru erori

  • nu stabilește o conexiune client-server!

    • se trimit direct datagrame
    • idee utilă atunci când nu este necesar / este prea costisitor să păstrăm o conexiune activă între entități
  • nu se garantează ordinea/corectitudinea pachetelor trimise (nu există a astfel de etapă de verificare)

  • prezintă overhead mic $\Rightarrow$ ieftin de implementat, dar nesigur

    • ex: Header UDP - 8 bytes VS Header TCP - 20 bytes
  • implementat de către Kernel-ul de Linux prin intermediul Socket API-ului; Network-Stack-ul devine responsabil de parsarea datagramelor UDP

image-20240308190244288

Schiță a implementării unui protocol de nivel Transport din Kernel (pseudocod):

vector <int> sockets;
pair <int, int> ports(socket, port);

// (1)
int create_unique_id() {
    int new_id = sockets[sockets.size() - 1] + 1;
    
    sockets.push(new_id);
    
    return new_id;
}

// (2)
void bind(int socket, int port) {
    ports.push((socket, port));
}

// (3)
void send(int socket, void *data, ... dest) {
    UDP_packet pkt;
    
    pkt.data = data;
    pkt.port_dst = dest.port;
    pkt.port_src = ...;	// random source port!
    
    send_ip(pkg, dest.ip);
}

// (4)
int recv(int socket) {
    pkt = packets.pop(port);
    UDP_packet p = (UDP_packet) pkt;
    
    verify_checksum(pkt);
    
    return p.data;
}

Concluzii UDP:

  • avantajos datorită vitezei

  • complexitate redusă & cost scăzut de implementare

  • pe baza lui se pot dezvolta alte protocoale

Îmbunătățiri posibile

1) Stop-and-Wait

  • se adaugă următoarele câmpuri la header-ul pachetelor: sequence_number, type (fiecare pe câte 2 octeți)
  • sender-ul trimite o datagramă UDP, așteaptă confirmarea receiver-ului printr-un pachet ACK, apoi trimite următoarea datagramă ș.a.m.d.
  • în cazul în care se pierde un pachet ACK, sender-ul așteaptă un interval de timp, după care retrimite pachetul inițial
  • dezavantaj: protocolul este unul lent

2) Select-and-Go

  • folosește fereastra glisantă
  • se trimite un număr de datagrame egal cu dimensiunea ferestrei (fiecare pachet va avea un seq_number asociat)
  • pentru fiecare datagramă se așteaptă un ACK de confirmare cu seq_number-ul corespunzător
  • dacă se pierde un pachet, ACK-urile primite vor avea seq_number-ul pachetului precedent; pachetul pierdut va fi retrimis, iar fereastra glisantă se va deplasa mai departe