Lectură laborator

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?

Click to display ⇲

Click to hide ⇱

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 care le ia unor date trimise printr-un mediu să ajungă la destinație
  • Round Trip Time (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.

Click to display ⇲

Click to hide ⇱

int recv_frame(char *buffer, int max_size)
{
      /* Am primit începutul de frame? */
      char c1, c2;
 
      c1 = recv_byte();
      c2 = recv_byte();
 
      while((c1 != DLE) && (c2 != STX)) {
         c1 = c2;
         c2 = recv_byte();
      }
 
      for (int i = 0; i < max_size; 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)
{
   /* Trimite delimitator */
   send_byte(DLE);
   send_byte(STX);
 
   /* Trimite bytes din frame */
   for (int i = 0; i < frame_size; i++) {
      /* Facem escape la escape */
      if (frame[i] == DLE)
        send_byte(DLE);
 
      send_byte(frame[i]);
   }
 
   /* Trimite delimitator final */
   send_byte(DLE);
   send_byte(ETX);
}

Exercitii

1. (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.

2. (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++. Mediul de transmisie este ideal, nu exista pierderi sau coruperi de mesaje. 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.

Daca vreti sa contribuiti la scheletul laboratoarelor, o puteti face prin intermediul unui pull request.

3. (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[30];
     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).

4. (1p) Vrem sa masuram latency-ul pentru a transmite un frame de 100 bytes si unul de 300. In sender vom trimite un frame ce contine un timestamp, in receiver vom masura latenta(diferenta de timp intre timestamp si timpul curent). Ce observam? (Puteti folosi orice metoda de masurare a timpului precum cele prezente articolul urmator.

O posibila rezolvare a laboratorului se gaseste aici.

pc/laboratoare/02.txt · Last modified: 2022/03/23 16:43 by vlad_andrei.badoiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0