This is an old revision of the document!
Pentru parcurgerea demo-urilor, folosim arhiva aferentă. Demo-urile rulează pe Linux. Descărcăm arhiva folosind comanda
wget http://elf.cs.pub.ro/so/res/cursuri/curs-11-demo.zip
și apoi decomprimăm arhiva
unzip curs-11-demo.zip
și accesăm directorul rezultat în urma decomprimării
cd curs-11-demo/
Acum putem parcurge secțiunile cu demo-uri de mai jos.
Ne propunem să urmărim modul în care se comportă comunicația între un client și un server pentru un număr mare de conexiuni și diverse configurații ale serverului. Vom varia dimensiunea bufferului de transmitere folosit de server și tipurile de implementare pentru server:
Pentru început vom genera 10.000 (zece mii) de fișiere a câte 100 KB. Vom rula scriptul
./create-files
Scriptul va dura câteva minute și va genera fișierele în forma fileXYZT
în subdirectorul in-data/
. Aceste fișiere vor fi prelucrate de server.
Pentru a obține executabilele de tip server aferente, vom folosi fișierul Makefile
:
make
În urma rulării comenzii make
rezultă patru fișiere executabile de tip server:
server
: executabil de tip server simplusendfile-server
: executabil de tip server cu suport sendfile (zero copy)threaded-server
: server multithreadedepoll-server
: server event-based
În continuare vom folosi fiecare dintre aceste servere pentru transferul celor 10.000 de fișiere create. Vom exemplifica în secțiunea de mai jos pentru serverul simplu (dat de executabilul server
) urmând ca aceeași pași să fie urmați și pentru celelalte trei servere.
Vom exemplifica scenariul de folosire a unui server pe fișierul server.c
și executabilul aferent server
. În cadrul acestui fișier se creează un socket TCP de tip listener care apoi așteaptă, secvențial, cereri de la clienți și le execută secvențial.
Presupunem că avem cele 10.000 de fișiere create în subdirectorul in-data/
. Serverul va aștepta conexiuni în care i se va preciza numele fișierelor pe care trebuie să le servească (unul pe conexiune).
Pentru început pornim serverul:
./server
Acum serverul este în starea de așteptare de conexiuni.
Pentru a genera conexiuni care să citească toate fișierele din subdirectorul in-data/
, rulăm, într-o altă consolă, scriptul aferent:
/usr/bin/time -v ./download-serial
Scriptul va dura de ordinul minutelor. Ca urmare a rulării acestui script fișierele vor fi transferate, prin sockeți locali (localhost) în subdirectorul out-data/
. Putem verifica transferul corect al acestora cu ajutorul comenzii:
diff -r in-data/ out-data/
Pentru a eficientiza transferul în partea clientului putem porni mai multe procese cu ajutorul scriptului
/usr/bin/time -v ./download-parallel
Scriptul va dura semnificativ mai puțin.
Motivul este că serverul livrează foarte rapid fișierele (sunt mici și multe) și este mai eficient să vină mai multe cereri simultane pentru a le servi. Nu la fel ar fi stat lucrurile dacă erau fișiere mai mari și mai puține.
Durata mare a rulării scriptului este datorată dimensiunii foarte mici a bufferului folosit în userspace pentru transfer. Observați în output-ul scripturile de mai sus numărul mare de schimbări de context realizate. Pentru a eficientiza acest lucru, vom altera dimensiunea bufferului, adică macro-ul BUFFERSIZE
de la valoarea 10
la valoarea 8192
. Vom recompila:
make
și apoi vom rula din nou cele două scripturi de download
/usr/bin/time -v ./download-serial /usr/bin/time -v ./download-parallel
Observăm că timpii au scăzut considerabil, la fel ca numărul de schimbări de context.
Aceeași pași ca mai sus pot fi realizați pentru celelalte trei servere:
sendfile-server
threaded-server
epoll-server
În cazul sendfile-server
, fiind vorba de un transfer tip zero-copy, nu avem o dimensiune de buffer aferentă; acesta nu va putea fi variată.
TODO