Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Exerciții

In cadrul laboratorului de astazi vom implementa o aplicatie de chat precum Whatsapp.

Descrierea scheletului

Pentru implementarea cerințelor, vom porni de la acest schelet de cod.

În scheletul de laborator găsiți implementată o aplicație client-server care implementează o funcție de chat, care funcționează astfel:

  • După pornire, serverul așteaptă conectarea a doi clienți
  • După ce ambi clienți s-au conectat, aceștia trimit mesaje către server, pentru a fi trimise către celălalt client.
  • La primirea unui mesaj, clientul afișează ce a primit.

Aplicația din schelet are câteva neajunsuri pe care le vom corecta.

Cerinte

Task 1


Note

TCP tratează informația transmisă ca pe un flux de date (octeții in ordine) și are un proces complex (cu ACK-uri, timere, etc.) care trebuie ascuns de utilizator (pentru a fi ușor de folosit). Astfel, apelul send() nu determină trimiterea imediată a unui mesaj/segment, ci face append datelor oferite la un buffer local de transmitere, trimiterea și recepționarea segmentelor de date fiind administrată de către stiva TCP/IP (implementată în kernel) în mod asincron.

La rândul său, recv() se deblochează atunci când orice cantitate de informație devine disponibilă în buffer-ul de recepție, neexistând o încadrare implicită (în mesaje) a octeților din flux.

În consecință, dacă protocolul de nivel aplicație vede transmisia ca fiind alcătuită din mesaje, atunci trebuie să ne așteptăm că este posibil să apară oricând:

  • trunchieri - din niște octeți trimiși de către o aplicație, în procesul de la distanță devine disponibilă doar o parte din ei, și totuși apelul recv() se întoarce, punând la dispoziția apelantului doar o parte din mesaj
  • concatenări - mai mult de un mesaj se citește cu un singur apel de recv().

Pentru a fi simplă identificarea mesajelor, implementarea din schelet trimite informația în calupuri de lungime fixată (sizeof(struct chat_meesage)), însă acest lucru nu este suficient deoare funcțiile recv() și send() pot recepționa / copia pentru trimitere mai puțini octeți decât am dat ca parametru.

Reimplementați funcțiile din common.h send_all() și recv_all() astfel încât să acoperiți acest neajuns.

Task 2

Alte neajunsuri ale aplicației sunt că:

  • Aceasta funcționează doar cu exact 2 clienți;
  • Clienții au o ordine fixată a comunicației (clientul x nu poate da mesaje când este rândul clientului y);
  • Ambii clienți întâi citesc un mesaj de la tastatură, apoi așteaptă să vadă ce primesc de la server. Asta face ca interactivitatea să fie afectată. Este un comportament așteptat înainte să rezolvăm task-ul 2.

Folosind API-ul de multiplexare (de exemplu, select(), poll() sau epoll()), urmăriți TODO-urile pentru a realiza o comunicare de tip chat între mai mulți clienți.


Funcționalități pentru a valida soluția:

  • serverul va accepta noi clienți în orice moment;
  • clienții vor putea comunica în orice ordine;
  • un mesaj primit de la un client va fi trimis către toți ceilalți, iar aceștia îl vor afișa imediat.

Task 3

La fiecare 4 secunde, server-ul va trimite un anunt despre abonamentele premium catre toti clientii: “Dragi clienti, pentru doar 12 lei o sa puteti trimite de 10 ori mai multe mesaje in jumatate din timp”. Vom folosi un timerfd pentru a implementa aceasta functionalitate.