This is an old revision of the document!
Laboratorul 02 - Datalink. Implementare framing folosind character stuffing
Lectură laborator
De citit înainte de laborator:
Lectură optională:
Materiale video opționale:
1. Noțiuni teoretice
Astăzi vom lucra la nivelul legăturii de date sau datalink. Vom folosi terminologia sender/receiver pentru a ne referi la cele două dispozitive care sunt conectate. Am văzut la curs faptul că nivelul physical ne pune la dispoziție un serviciu pentru a trimite un flux de biți între două dispozitive direct conectate. Prin urmare, ne putem imagina un nivel data-link naiv, care presupune că toate perechile de dispozitive sunt conectate direct. De ex, o rețea de telefonie fără centrală. Dar, ce ne facem dacă vrem să conectăm 1000 de dispozitive(e.g. WiFi)? Dar 1000000?. O optimizarea ar fi adăugarea unor cabluri partajate de mai multe semnale. Astfel, apare conceptul de frame, o unitate de transmisie delimitată în timp pe un mediu fizic.
Bit stuffing
Cum nivelul fizic ne permite transmisia de date la nivel de bit, ne punem problem de a trimite cantități mai mari de date deodată.
Soluția acestei probleme o reprezinta bit stuffing. Mai exact, folosim 01111110
ca și delimitator intre frame-urile de biți pe care vrem sa le trimitem.
De exemplu, dacă vrem sa trimitem 0100
atunci o sa îl codam ca și 01111110|0100|01111110
.
Cum vom proceda daca vrem sa trimitem 01111110
?
01111110|011111010|01111110
Unde se intampla transmisia?
Legătura de Date si Retea sunt procese independente ce comunica prin schimburi de mesaje. Procesele ce țin de nivelul Fizic și de sub-layerul Media Access Control din Data Link rulează pe hardware dedicat (de exemplu, Network Interface Card (NIC)). Restul proceselor executate de Data Link și de Network se executa pe CPU, prin sistemul de operare. În figură, putem observa o implementare.
Metrici
Ne interesează sa definim următoarele metrici:
Bandwidth - se măsoară în biți / secunda și reprezinta cantitatea de informație care poate fi transmisa într-o unitate de timp pe legătura de date
Latency - se măsoară în secunde și reprezinta timpul pe care îl ia unor date trimise printr-un mediu să ajungă la destinație
Round Time Trip (RTT) - reprezinta timpul scurs din momentul în care un cadru este trimis pana în momentul în care este primită confirmarea.
Legătura de date poate fi asemănata cu un cilindru în care datele sunt introduse de către transmițător și primite de către receptor. Aria secțiunii cilindrului reprezinta viteza de transmisie, iar înălțimea este timpul de propagare.
Volumul cilindrului determina cantitatea de informație aflată pe legătura de date, la un anumit moment de timp. Deci, cantitatea de informație aflata pe fir la un anumit moment de timp este: Bandwidth × Delay.
2. Character stuffing în practică
Cum in software ne este mult mai ușor sa lucram la nivel de byte decât bit, nivelul fizic ne oferă și un serviciu de trimitere de fluxuri de bytes. În mod similar cu bit stuffing, vom folosi mai multe caractere speciale pentru a ne delimita frame-ul. ASCII table
A B C ⇒ DLE STX A B C DLE ETX
A B C DLE STX D ⇒ DLE STX A B C DLE DLE STX D DLE ETX
Mai jos avem o diagrama care surprinde transmisia de date folosind framing. Vedem cum la nivelul DataLink folosind protocolul nostru simplu cu bytes de separare putem oferi un serviciu de trimitere de frames.
Următorul exemplu prezintă o posibila implementare de character stuffing folosind DEL
,STX
si ETX
. Presupunem că am cumpărat o placa de rețea (NIC) care are în firmware doua funcții send_byte
si recv_byte
.
int recv_frame(char *buffer, int max_size)
{
/* Am primit începutul de frame? */
if (!((recv_byte() == DLE) && (recv_byte() == STX)))
return -1;
for (int i = 0; i < max_byte; i++) {
char byte = recv_byte();
if (byte == DLE) {
byte = recv_byte();
if (byte == ETX)
return i;
else if (byte != DLE)
return -1;
}
buffer[i] = byte;
}
return max_size;
}
Transmițătorul, mult mai ușor poate fi implementat astfel.
void send_frame(char *frame, int frame_size)
{
send_byte(DLE);
send_byte(STX);
for (int i = 0; i < frame_size; i++) {
if (frame[1] == DLE)
send_byte(DLE);
send_byte(frame[i]);
}
send_byte(DLE);
send_byte(ETX);
}
Exercitii
(3p) Calculați bandwidth-ul și latency-ul pentru următoarele medii de transmisie:
Mesagerie pe baza de porumbei. În trecut, porumbeii erau folosiți pentru a transporta mesaje intre doua locații. Presupunem că vrem să trimitem un USB de 16
GB din București pana la Cluj (400 km). Calculați bandwidth și latency pentru un porumbel care zboară cu 80 km/h
Tub pneumatic. Introduse in secolul 19, tuburile pneumatice au fost folosite pentru a transmite mesaje urgente intre clădiri sau chiar orașe. Capsula atinge o viteză de 8 m/s în tranzit. Presupunând că trimitem un HDD de 2 TB din clădirea automaticii către rectorat(200m), calculați bandwidth-ul și latency-ul.
(4p) Vrem sa implementam un mic protocol de nivel datalink care folosește tehnica byte stuffing pentru a trimite mesaje de tip string. Laboratorul poate fi implementat atât in C cat si C++.
Scheletul laboratorului se găsește aici, tot acolo se găsește și un README.md cu funcționalitatea disponibila. Avem la dispoziție următorul
API expus de către nivelul Physical
/* Trimite un caracter celuilalt capăt prin nivelul fizic */
int send_byte(char c);
/* Primește un caracter de la celalalt capăt, dacă nu a fost nimic transmis, returnează un caracter aleator */
char recv_byte();
Executați scriptul ./run_experiment.sh pentru a observa un demo al funcționalitaților disponibile. Îl puteți folosi în testarea codului, acesta pornind simulatorul de data link, rulând ./recv si ./send.
(2p) Acum ca am reușit sa trimitem primele noastre frame-uri care conțin șiruri de caractere, vrem sa extindem funcționalitatea pentru a trimite data in format binar. Vrem să trimitem următoarea structura de date.
struct Packet {
int size; /* size inainte lui payload pentru a sti dinainte dimensiunea */
char payload[100];
int sum;
};
Un sir de caractere precum char buffer[1024]
reprezintă un sir de bytes, astfel putem face operații precum (struct Packet) buffer
sau memcpy(buffer, &packet, sizeof(struct Packet)
.
(1p) Vrem sa masuram latency-ul pentru a transmite un frame de 100 bytes si unul de 300. Ce observam? (Puteti folosi orice metoda de masurare a timpului precum cele prezente in standardul POSIX, de exemplu
gettimeofday.