Sistem DE Partajare AL Fișierelor ÎN Rețea

SISTEM DE PARTAJARE AL FIȘIERELOR ÎN REȚEA

Cuprins

Introducere……………………………………………………………………………………….4

1.1. Utilizarea rețelelor ………………………………………………………………………………………….4

1.1.1. Rețele pentru firme ……………………………………………………………………………5

1.1.2. Rețele pentru oameni………………………………………………………………………….6

1.2. Partea hardware a rețelelor……………………………………………………………………………….7

1.2.1. Rețele locale……………………………………………………………………………………..8

1.2.2. Rețele metropolitane………………………………………………………………………….8

1.2.3. Rețele larg răspândite geografic…………………………………………………………..9

Modele de referință………………………………………………………………………….10

2.1. Modelul de referință OSI………………………………………………………………………………..10

2.1.1. Nivelul Fizic……………………………………………………………………………………10

2.1.2. Nivelul Legătură de date…………………………………………………………………..10

2.1.3. Nivelul Rețea…………………………………………………………………………………..11

2.1.4. Nivelul Transport……………………………………………………………………………..11

2.1.5. Nivelul Sesiune………………………………………………………………………………..12

2.1.6. Nivelul Prezentare……………………………………………………………………………13

2.1.7. Nivelul Aplicație………………………………………………………………………………13

2.2. Modelul de referință TCP/IP…………………………………………………………………………..14

2.2.1. Nivelul Internet……………………………………………………………………………….15

2.2.2. Nivelul Transport……………………………………………………………………………..16

2.2.3 Nivelul Aplicație……………………………………………………………………………….16

2.2.4 Nivelul Gazdă la rețea……………………………………………………………………….17

2.3. Comparație între Modelul OSI și Modelul TCP/IP…………………………………………….17

Tehnologii utilizate…………………………………………………………………………..18

3.1. Modelul Client – Server…………………………………………………………………………………18

3.1.1. Server…………………………………………………………………………………………….18

3.1.2. Client……………………………………………………………………………………………..18

3.2. Familia de protocoale TCP/IP…………………………………………………………………………19

3.3. Comparație între protocoalele TCP și UDP……………………………………………………….21

3.4. Comparație între protocoalele IPv4 și IPv6…………………………………………………….24

Detalii de implementare…………………………………………………………………..25

4.1. Setarea serverului…………………………………………………………………………………………25

4.2. Conectarea clienților…………………………………………………………………………………….26

4.3. Multiplexarea comunicației…………………………………………………………………………..29

4.4. Implementarea comenzilor client……………………………………………………………………31

4.4.1. Listclients………………………………………………………………………………………31

4.4.2. Infoclient……………………………………………………………………………………….31

4.4.3. Message………………………………………………………………………………………..32

4.4.4. Sharefile………………………………………………………………………………………..34

4.4.5. Unsharefile…………………………………………………………………………………….35

4.4.6. Getshare………………………………………………………………………………………..36

4.4.7. Getfile…………………………………………………………………………………………..36

4.4.8. Quit………………………………………………………………………………………………39

4.5. Implementarea comenzilor server…………………………………………………………………..41

4.5.1. Status…………………………………………………………………………………………….41

4.5.2. Log………………………………………………………………………………………………..41

4.5.2. Quit……………………………………………………………………………………………….42

4.6. Probleme în implementare……………………………………………………………………………..42

Concluzii…………………………………………………………………………………………43

Bibliografie………………………………………………………………………………………..

Introducere

În secolul XX, tehnologia dominantă este bazată pe colectarea, prelucrarea și distribuirea informației. Tehnologia a evoluat foarte mult, astfel că am asistat la invenția radioului și a televiziunii, la creșterea industriei de calculatoare și la lansarea satelițiilor de comunicații.

Organizațiile mari, care sunt răspândite pe o suprafață geografică mare, se așteaptă ca printr-o simplă comandă să acceseze și cele mai îndepărtate echipamente ale lor. Aceste organizații se bazează pe un model în care munca este făcută de un număr mare de calculatoare interconectate. Acest model se numește rețea de calculatoare. Două calculatoare sunt interconectate dacă pot să schimbe informații între ele. Conectarea lor se poate face prin cabluri de cupru, fibră optică sau wireless(fără cablu).

Utilizarea rețelelor

Rețele pentru firme:

Organizațiile mari, care dispun de un număr mare de calculatoare, au nevoie de a centraliza toate datele de pe fiecare calculator, și pentru asta calculatoarele trebuie să fie interconectate într-o rețea. Într-o rețea de calculatoare un lucru important este reprezentat de împărțirea resurselor. Toate echipamentele sunt disponibile pentru oricine se află în rețea (Ex: imprimanta), indiferent de locația resursei sau a utilizatorului. Altfel spus, dacă un utilizator se află la 2000 de km de datele pe care le caută, poate folosi acele date ca și cum ar fi locale.

Un alt scop al rețelelor pentru firme poate fi asigurarea unei fiabilități mari prin accesul la mai multe echipamente de stocare. Fișierele pot fi copiate pe mai multe calculatoare, astfel încât, dacă unul nu poate fi disponibil, se pot utiliza celelalte. În domeniul bancar o defactare a unui calculator poate fi critică. De aceea și aici se folosește stocarea datelor pe mai mult mașini.

Firmele au fost determinate să construiască sisteme formate din calculatoare, câte unul pentru fiecare utilizator, datele din rețea fiind păstrate pe unul sau mai multe servere de fișiere. Acest model se numește model client-server și este ilustrat in „Figura 1”.

Motivul a fost economisirea banilor. Raportul preț/calitate al calculatoarelor mici este mult mai bun decât al calculatoarelor mari. De exemplu un calculator mare este de zece ori mai performant decât un calculator mic și este de o mie de ori mai scump.

Figura 1

Scalabilitatea este un alt scop al conectării in rețea. Acest lucru presupune ca odată cu creșterea volumului de date să crească și performanța sistemului prin adăugarea de noi procesoare. În modelul client-server pot fi adăugați clienți noi și servere atunci cand este nevoie de ei. Problema se complică în cazul sistemelor mari de calcul, deoarece el trebuie înlocuit cu un sistem mai mare, ceea ce provoacă de obicei costuri mari si neplăceri utilizatorilor.

O rețea de calculatoare poate reprezenta și un mediu puternic de comunicare între angajații aflați la mare depărtare unul de celalalt. Ei pot lucra la un document împreuna chiar dacă trăiesc în locuri diferite. Pe termen lung, utilizarea rețelelor pentru comunicarea inter-umana, va fi mai importantă decât creșterea fiabilității.

Rețele pentru oameni:

Rețelele sunt la fel de importante pentru oameni ca și pentru firme. Accesul la informații de la distanță, comunicarea la distanță sau divertismentul sunt lucrurile fascinante care au început să se petreacă odată cu dezvoltarea rețelelor. Exemple pentru accesarea informațiilor la distanța pot fi multe. Unul ar fi că mulți oameni își plătesc online taxele și iși administreaza electronic investițiile și conturile bancare. Se pot face cumpărături la domiciliu, și se pot vizualiza cataloage online.

Presa este deja peste tot pe internet, utilizatorul putând sa opteze pentru informațiile care îl intereseaza. De exemplu ar putea bifa că nu vrea informații despre lumea mondenă și nu va primii aceste informații. De asemenea utilizatorul are acces și la alte informații precum: afaceri, politică, rețete culinare, știință, călătorii, istorie, sănătate și multe alte domenii.

O altă utilizare a rețelei este reprezentată de poșta electronică și serviciul de mesagerie instantă. Poșta electronică este folosită de milioane de oameni, iar în scurt timp, pe lângă text va conține secvențe audio și video. Serviciul de mesagerie instantă permite utilizatorilor să comunice la distanță fără întârziere. Această tehnologie face posibile videoconferințele între oamenii aflați la distanță. Întâlnirile pot fi folosite pentru educație la distanță spre exemplu. dar și multe alte aplicații.

Divertismentul reprezintă o industrie în continuă creștere. Putem viziona o gamă foarte mare de filme, iar în viitor acestea pot deveni interactive: de exemplu un film cu două finaluri. Spectatorul va fi intrebat spre care final să continue filmul.

Pe de altă parte, jocurile video reprezintă aplicația de succes. Există deja jocuri pentru mai multe persoane, cu animație tridimensională, in care realitatea virtuală este partajată.

Partea Hardware a rețelelor

Există două criterii după care pot fi repartizate rețelele: tehnologia de transmisie și scara la care operează. În funcție de tehnologia de transmisie rețelele pot fi de două tipuri:

rețele cu difuzare;

rețele punct la punct.

Rețelele cu difuzare se referă la un singur canal de comunicație care este partajat de toate calculatoarele din rețea. Orice calculator poate trimite pe acest canal pachete care sunt recepționate de toate celelalte calculatoare din rețea. La recepționare, calculatorul verifică dacă pachetul îi este adresat printr-un câmp (câmpul de adresă din pachet), iar dacă îi este adresat îl prelucrează, altfel îl ignoră. Sistemele cu difuzare permit și trimiterea unui pachet adresat tuturor mașinilor din rețea, prin folosirea unui cod special în câmpul de adresă.

Rețelele punct la punct sunt formate din numeroase conexiuni între perechi de mașini. Când se trimite un pachet pe o astfel de rețea, acesta va trece prin ………………….

Introducere

În secolul XX, tehnologia dominantă este bazată pe colectarea, prelucrarea și distribuirea informației. Tehnologia a evoluat foarte mult, astfel că am asistat la invenția radioului și a televiziunii, la creșterea industriei de calculatoare și la lansarea satelițiilor de comunicații.

Organizațiile mari, care sunt răspândite pe o suprafață geografică mare, se așteaptă ca printr-o simplă comandă să acceseze și cele mai îndepărtate echipamente ale lor. Aceste organizații se bazează pe un model în care munca este făcută de un număr mare de calculatoare interconectate. Acest model se numește rețea de calculatoare. Două calculatoare sunt interconectate dacă pot să schimbe informații între ele. Conectarea lor se poate face prin cabluri de cupru, fibră optică sau wireless(fără cablu).

Utilizarea rețelelor

Rețele pentru firme:

Organizațiile mari, care dispun de un număr mare de calculatoare, au nevoie de a centraliza toate datele de pe fiecare calculator, și pentru asta calculatoarele trebuie să fie interconectate într-o rețea. Într-o rețea de calculatoare un lucru important este reprezentat de împărțirea resurselor. Toate echipamentele sunt disponibile pentru oricine se află în rețea (Ex: imprimanta), indiferent de locația resursei sau a utilizatorului. Altfel spus, dacă un utilizator se află la 2000 de km de datele pe care le caută, poate folosi acele date ca și cum ar fi locale.

Un alt scop al rețelelor pentru firme poate fi asigurarea unei fiabilități mari prin accesul la mai multe echipamente de stocare. Fișierele pot fi copiate pe mai multe calculatoare, astfel încât, dacă unul nu poate fi disponibil, se pot utiliza celelalte. În domeniul bancar o defactare a unui calculator poate fi critică. De aceea și aici se folosește stocarea datelor pe mai mult mașini.

Firmele au fost determinate să construiască sisteme formate din calculatoare, câte unul pentru fiecare utilizator, datele din rețea fiind păstrate pe unul sau mai multe servere de fișiere. Acest model se numește model client-server și este ilustrat in „Figura 1”.

Motivul a fost economisirea banilor. Raportul preț/calitate al calculatoarelor mici este mult mai bun decât al calculatoarelor mari. De exemplu un calculator mare este de zece ori mai performant decât un calculator mic și este de o mie de ori mai scump.

Figura 1

Scalabilitatea este un alt scop al conectării in rețea. Acest lucru presupune ca odată cu creșterea volumului de date să crească și performanța sistemului prin adăugarea de noi procesoare. În modelul client-server pot fi adăugați clienți noi și servere atunci cand este nevoie de ei. Problema se complică în cazul sistemelor mari de calcul, deoarece el trebuie înlocuit cu un sistem mai mare, ceea ce provoacă de obicei costuri mari si neplăceri utilizatorilor.

O rețea de calculatoare poate reprezenta și un mediu puternic de comunicare între angajații aflați la mare depărtare unul de celalalt. Ei pot lucra la un document împreuna chiar dacă trăiesc în locuri diferite. Pe termen lung, utilizarea rețelelor pentru comunicarea inter-umana, va fi mai importantă decât creșterea fiabilității.

Rețele pentru oameni:

Rețelele sunt la fel de importante pentru oameni ca și pentru firme. Accesul la informații de la distanță, comunicarea la distanță sau divertismentul sunt lucrurile fascinante care au început să se petreacă odată cu dezvoltarea rețelelor. Exemple pentru accesarea informațiilor la distanța pot fi multe. Unul ar fi că mulți oameni își plătesc online taxele și iși administreaza electronic investițiile și conturile bancare. Se pot face cumpărături la domiciliu, și se pot vizualiza cataloage online.

Presa este deja peste tot pe internet, utilizatorul putând sa opteze pentru informațiile care îl intereseaza. De exemplu ar putea bifa că nu vrea informații despre lumea mondenă și nu va primii aceste informații. De asemenea utilizatorul are acces și la alte informații precum: afaceri, politică, rețete culinare, știință, călătorii, istorie, sănătate și multe alte domenii.

O altă utilizare a rețelei este reprezentată de poșta electronică și serviciul de mesagerie instantă. Poșta electronică este folosită de milioane de oameni, iar în scurt timp, pe lângă text va conține secvențe audio și video. Serviciul de mesagerie instantă permite utilizatorilor să comunice la distanță fără întârziere. Această tehnologie face posibile videoconferințele între oamenii aflați la distanță. Întâlnirile pot fi folosite pentru educație la distanță spre exemplu. dar și multe alte aplicații.

Divertismentul reprezintă o industrie în continuă creștere. Putem viziona o gamă foarte mare de filme, iar în viitor acestea pot deveni interactive: de exemplu un film cu două finaluri. Spectatorul va fi intrebat spre care final să continue filmul.

Pe de altă parte, jocurile video reprezintă aplicația de succes. Există deja jocuri pentru mai multe persoane, cu animație tridimensională, in care realitatea virtuală este partajată.

Partea Hardware a rețelelor

Există două criterii după care pot fi repartizate rețelele: tehnologia de transmisie și scara la care operează. În funcție de tehnologia de transmisie rețelele pot fi de două tipuri:

rețele cu difuzare;

rețele punct la punct.

Rețelele cu difuzare se referă la un singur canal de comunicație care este partajat de toate calculatoarele din rețea. Orice calculator poate trimite pe acest canal pachete care sunt recepționate de toate celelalte calculatoare din rețea. La recepționare, calculatorul verifică dacă pachetul îi este adresat printr-un câmp (câmpul de adresă din pachet), iar dacă îi este adresat îl prelucrează, altfel îl ignoră. Sistemele cu difuzare permit și trimiterea unui pachet adresat tuturor mașinilor din rețea, prin folosirea unui cod special în câmpul de adresă.

Rețelele punct la punct sunt formate din numeroase conexiuni între perechi de mașini. Când se trimite un pachet pe o astfel de rețea, acesta va trece prin mai multe mașini intermediare până să ajungă la destinație. Algoritmii sunt foarte importanti în acest caz pentru dirijarea pachetelor. În general, rețelele mici folosesc difuzarea, în timp ce rețelele mai mari sunt rețele punct la punct.

Rețelele se clasifică și după mărime. Distingem astfel patru tipuri de rețele:

Rețeaua locală(LAN) – care se poate întinde pe o suprafață de la 1 pâna la 1000m. De exemplu o cameră, o clădire sau un campus;

Rețeaua metropolitană(MAN) – care acoperă suprafața unui oraș intreg;

Rețeaua răspândită larg geografic (WAN) – care acoperă o suprafață de la 100 la 1000km. De exemplu o țară sau un continent.

Internetul. Acoperă suprafața unei planete face posibilă comunicarea între tipurile de rețele precedente.

Rețelele locale:

Denumite și LAN-uri (Local Area Networks) sunt rețele private care se întind pe o suprafața de cel mult câțiva kilometrii. Sunt localizate de obicei într-o clădire sau într-un campus. Sunt des folosite în cadrul companiilor și fabricilor pentru a interconecta calculatoarele personale cu scopul de a partaja resurse (Ex: imprimanta) și de a schimba informații.

LAN-urile au dimensiuni restrânse, ceea ce înseamnă că timpul de transmisie în cazul cel mai defavorabil este limitat și cunoscut dinainte. Putem utiliza anumite tehnici de proiectare și totodată administrarea rețelei se simplifică.

LAN-urile folosesc o tehnologie de transmisie în care toate calculatoarele sunt legate la un singur cablu. Funcționează la viteze cuprinse între 10 și 100 MBps, au întârzieri mici și produc erori foarte puține.

Un exemplu de LAN este ilustrat în „Figura 2”.

Figura 2

Rețele metropolitane

Denumite și MAN-uri sunt versiuni extinse ale LAN-urilor și utilizează tehnologii similare cu acestea. O rețea metropolitană se poate întinde pe suprafața unui oraș intreg și poate fi atât privată cât și publică.

O rețea metropolitană poate suporta atât date cât și voce și poate chiar să aibă legături cu rețeaua locală de televiziune prin cablu. Aceasta dispune numai de un cablu sau două, fără să conțină elemente de comutare care deviază pachetele pe una din cele câteva posibile linii de ieșire. Nefiind necesară comutarea, proiectarea este mai simplă.

Rețelele larg răspândite geografic

Denumite și WAN(Wide Area Network) acoperă o arie geografică mare, cum ar fi o țară sau chiar un continent. În acest tip de rețea calculatoarele sunt conectate printr-o subrețea. Sarcina subrețelei este de a transporta pachete de la calculator la calculator. În majoritatea WAN-urilor, subrețeaua este formată din două elemente: liniile de transmisie și elementele de comutare.

Liniile de transmisie transportă biții între calculatoare. Elementele de comutare sunt calculatoare specializate, folosite pentru a conecta liniile de transmisie. Când sosesc date pe o anumită linie, elementul de comutare trebuie sa aleagă o nouă linie pentru a trimite datele mai departe. Aceste elemente de comutare se numesc routere.

Rețelele sunt organizate sub forma de straturi sau niveluri, construite unul peste celălalt.

Numarul nivelurilor și funcția acestora variază de la o rețea la alta. Scopul fiecărui nivel este de a oferi servicii nivelurilor superioare. Totodată nivelurile superioare sunt protejate asupra detaliilor de implementare.

Nivelul „x” de pe o mașină comunică cu nivelul „x” de pe altă mașină sub anumite reguli care sunt cunoscute sub numele de protocol (protocolul nivelului „x”). Un protocol reprezintă modul în care nivelurile comunică între ele. În „Figura 3” este ilustrat un model cu cinci niveluri.

Figura 3

Datele nu sunt transferate de pe nivelul „x” al unui calculator pe nivelul „x” al altui calculator în mod direct. Mai întâi datele sunt transferate în nivelurile inferioare până când informația ajunge in mediul fizic. Datele sunt preluate din mediul fizic de nivelul 1 al mașinii destinație si transferate la nivelurile superioare.

Între doua niveluri adiacente, există o interfață. Aceasta definește serviciile și operațiile pe care nivelul superior le oferă nivelului inferior. Interfețele clare se referă la faptul că pe langă minimizarea volumului de informații care trebuie transferat, acestea permit o înlocuire mai simplă a implementării unui nivel cu o implementare diferită.

Modele de referință

În continuare vor fi prezentate două modele de referință

Modelul de referință OSI;

Modelul de referință TCP/IP.

Modelul de referință OSI

Modelul este format din șapte niveluri. Acestea sunt:

Nivelul Aplicație,

Nivelul Prezentare,

Nivelul Sesiune,

Nivelul Transport,

Nivelul Rețea,

Nivelul Legătură de date

Nivelul Fizic.

Pentru a se ajunge la cele șapte niveluri sunt aplicate următoarele principii:

Un nou nivel se creează atunci când este nevoie de un nou nivel de abstractizare.

Fiecare nivel indeplinește un rol foarte bine definit.

Delimitarea nivelurilor se face astfel încât fluxul de informații prin interfețe sa fie minim.

Nivelul fizic

Stratul fizic, stratul cel mai de jos al modelului OSI, este preocupat cu transmiterea biților printr-un canal de comunicație, fără să se preocupe de semnificația sau de structura lor. Proiectarea trebuie să asigure că atunci când la un capăt se trimite bitul 0, în cealaltă parte sa fie receptat ca un bit 0 și nu ca un bit 1. Problema se rezumă la câți volți sunt folosiți pentru a reprezenta valoarea 0 și câți pentru a reprezenta un 1.

Nivelul legătură de date

Acest nivel are sarcina de a descompune datele de intrare în cadre de date, să le transmită secvențial și să prelucreze cadrele de confirmare trimise înapoi de receptor. Marcarea și recunoașterea delimitatorilor între cadre este facută de nivelul legatură de date. Această marcare se face prin atașarea la început sau la sfarșit a unor șabloane speciale de biți. Șabloanele speciale pot apărea și accidental in datele respective și trebuie luate măsuri speciale pentru acest caz astfel încât ele să nu fie interpretate incorect.

Un cadru poate fi distrus total din cauza unui zgomot apărut pe linie. În acest caz, nivelul de legătură de date de pe calculatorul sursă poate să retrimită cadrul. Transmiterea multiplă a unui cadru duce la posibilitatea de apariție a cadrelor duplicate. Un cadru duplicat poate apărea in cazul în care se pierd cadrele de confirmare primite de emițător de la receptor. Nivelului legătură de date îi revine sarcina de a rezolva problemele cadrelor deteriorate, pierdute sau duplicate.

O alta problemă care apare la majoritatea nivelurilor, dar și la nivelul legătură de date este inundarea unui receptor lent cu date primite de la un emițător rapid. În acest caz sunt necesare mecanisme de reglare a traficului care să permită emițătorului să afle câtă memorie tampon are receptorul in acel moment.

Deoarece linia este pentru transmisia datelor în ambele sensuri, apare o nouă problemă care este rezolvată de programele de la nivelul legătură de date. Această problemă se referă la concurența care există pentru utilizarea liniei între cadrele de confirmare pentru transmiterea datelor de la “mașina 1” la “mașina 2” și cadrele de confirmare pentru transmiterea datelor de la “mașina 2” la “mașina 1”.

Nivelul rețea

Acest nivel se ocupă de controlul subrețelei. Determinarea modului în care datele sunt dirijate de la sursă la destinație este una dintre probleme. Dirijarea este foarte dinamică, trasele pachetelor fiind stabilite în raport cu traficul din rețea.

Daca sunt prea multe pachete în același timp în subrețea, se va produce o congestie a subrețelei, iar controlul acesteia îi revine tot nivelului rețea.

Pot apărea multe probleme când un pachet este transmis dintr-o rețea în alta pentru a ajunge la receptor. Modul de adresare diferă de la rețea la rețea, astfel că una dintre rețele poate chiar să nu accepte pachetul din cauză că este prea mare. De asemenea și protocoalele de nivel pot fi diferite. Aceste probleme sunt rezolvate de nivelul rețea.

Nivelul transport

Rolul acestui nivel este de a accepta datele de la nivelul sesiune și de a le descompune în unități mai mici, să transmită aceste unități nivelului inferior și să se asigure că toate datele sosesc corect la celălalt capăt. Acest lucru trebuie făcut eficient, izolând nivelurile superioare de modificările inevitabile în tehnologia echipamentelor.

Nivelul transport determină tipul de serviciu furnizat nivelului sesiune și utilizatorilor rețelei. Pentru a primi mesajele sau octeții în ordinea în care aceștia au fost trimiși, nivelul transport foloseste o conexiune punct la punct fără erori.

Un serviciu important pe care nivelul transport îl oferă este multiplexarea comunicației pe un singur canal. Acest lucru este implementat și în aplicația care urmează să fie prezentată.

Alte servicii pe care nivelul transport le mai poate oferii sunt: transportul mesajelor individuale fără garanție privind ordinea de livrare și trimiterea mesajelor către mai multe destinații.

Spre deosebire de nivelurile 1-3, care sunt înlănțuite, nivelul transport este un nivel cap la cap, de la sursă la destinație. Altfel spus un program de pe calculatorul sursă comunică cu un program similar de pe calculatorul destinație cu ajutorul mesajelor de control. În nivelurile 1-3 protocoalele de nivel au loc între fiecare calculator și vecinii săi imediați, nu direct între sursă și destinație, care pot fi separate de mai multe rutere.

Informația pentru a diferenția mesajele și a știi care mesaj aparține cărei conexiuni se pune în antetul de transport.

De asemenea este nevoie de un mecanism pentru reglarea fluxului de date, astfel încât o unitate lentă să nu fie suprasolicitată de o unitate rapidă. Acest mecanism se numește controlul fluxului și este foarte important în nivelul transport.

Nivelul sesiune

Acest nivel permite utilizatorilor de pe stații diferite să stabilească sesiuni între ei. O sesiune, în afară de transportul obișnuit de date, furnizează și servicii de îmbunatățire care sunt de folos în unele aplicații.

Controlul dialogului este unul dintre serviciile nivelului. Sesiunile pot permite ca traficul sa fie făcut în ambele sensuri în același timp, sau doar într-un anumit sens. Dacă traficul se realizeată într-un singur sens, nivelul sesiune ține evidența gazdelor care vor să transmită.

Gestionarea jetonului este un serviciu sesiune care este esențial ca două părți să nu realizeze aceeași operație simultan. Pentru rezolvarea acestei situații, nivelul dispune de jetoane care pot circula între mașini. Doar mașina care deține jetonul poate să realizeze operația.

Un alt serviciu al nivelului sesiune este sincronizarea. De exemplu dacă vrem sa transferăm un fișier între două mașini, și durata acestui transfer este de o oră, iar timpul de cădere a legăturii este de 30 de minute, după fiecare eșec, transferul va fi inițiat din nou și poate nu va reușii nici data viitoare. Pentru a elimina această problemă, nivelul sesiune dispune de o modalitate de a introduce puncte de control în fluxul de date, iar reluarea transferului se va face după utimul punct de control.

Nivelul prezentare

Spre deosebire de niveluirle inferioare, care se ocupa cu transferul sigur al biților de la o unitate la alta, acest nivel se ocupă de sintaxa și semantica informațiilor transmise.

Nivelul prezentare oferă servicii de criptare și decriptare a datelor pentru a asigura securitatea comunicației în rețea. Transferul de date între sisteme de tipuri diferite(Ex: Unix-DOS), necesită criptarea datelor în funcție de caracteristicile acestora.

Programele folosite de utilizatori nu interschimbă șiruri aleatoare de biți, dar date care reprezintă nume, adrese, sume de bani, locații, aceste informații sunt reprezentate prin structuri de date care diferă de la calculator la calculator. Pentru a face posibilă comunicarea, structurile de date sunt definite într-un mod abstract împreună cu o codificare standardizată.

Nivelul aplicație

Acest nivel conține o mulțime de protocoale foarte utilzate. În lume sunt sute de tipuri de terminale incompatibile. Este dificil de a lucra într-o rețea cu multe tipuri diferite de terminale, fiecare cu secvențe ESCAPE diferite pentru editarea textului și mutarea cursorului.

O modalitate pentru rezolvarea acestei probleme este definirea unui terminal virtual de rețea abstract , și scrierea unor programe care pot sa lucreze cu acesta. Pentru a putea lucra cu orice tip de terminal , avem nevoie de un program care să facă o corespondență între funcțiile terminalului real și cel virtual. De exemplu atunci cand vrem să mutăm cursorul într-un anumit colț al ecranului, programul trebuie să mute și cursorul terminalului real în aceeași poziție.

Un alt rol al nivelului aplicație este transferul fișierelor. Sistemele au convenții diferite de nume și moduri diferite de a reprezenta liniile de text. Transferul fișierelor între sisteme presupune rezolvarea acestor incompatibilități. Nivelul aplicație iși asumă și acest rol.

În figura de mai jos este reprezentat modelul cu cele șapte niveluri ale sale și protocoalele de comunicație dintre ele.

Modelul de referință TCP/IP

Modelul a fost necesar pentru a conecta mai multe tipuri de rețea. Spre deosebire de modelul OSI, modelul TCP/IP este format din patru niveluri:

Nivelul Gazdă la rețea

Nivelul Internet

Nivelul Transport

Nivelul Aplicație

Nivelul Sesiune și nivelul Prezentare nu există în acest model.

Nivelul Internet

Obiectivul nivelului Internet este să asigure rutarea pachetelor în interiorul unei singure rețele. Nivelul dispune de funcționalități de comunicare între două rețele, una sursă și alta destinație. Nivelul Internet este axul principal al întregii arhitecturi. Permite gazdelor să trimită pachete în orice rețea, iar pachetele circulă independent până la destinație. Pachetele pot sosi într-o altă ordine față de ordinea în care au fost trimise, și daca se dorește ordonarea pachetelor, nivelurile de mai sus vor prelua această sarcină.

Mai jos, în următoarea figură, sunt prezentate nivelurile modelului OSI în comparație cu nivelurile modelului TCP/IP.

Determinarea drumului optim între rețeaua sursă și rețeaua destinație se face la acest nivel. În protocolul IPv4, integritatea pachetelor este asigurată de sume de control. Acest lucru nu se întamplă și cu IPv6. Diferențele dintre IPv4 și IPv6 vor fi prezentate în următoarele capitole.

Nivelul Internet din modelul TCP/IP funcționează asemănător cu nivelul Rețea din modelul OSI. Se poate face o analogie cu sistemul de poștă clasică. O persoană poate depune mai multe scrisori într-o cutie poștală cu destinație internațională și aproape toate scrisorile vor ajunge la destinația corectă. Pe drum, scrisorile trec prin mai multe oficii poștale, dar acest lucru este invizibil pentru beneficiari. Fiecare țară are propriile timbre și propriile reguli de livrare, insă și lucrul acesta este ascuns utilizatorilor.

Nivelul Transport

Acest nivel este superior nivelului Internet, și este proiectat la fel ca nivelul Transport din modelul OSI. Pentru comunicarea dintre perechile sursă – destinație au fost definite două protocoale capăt la capăt, TCP și UDP.

TCP(Transmision Control Protocol – protocolul de control al transmisiei) împarte fluxul de octeți în mai multe mesaje și le trimite nivelului Internet. La destinație, mesajele sunt reasamblate de procesul receptor TCP. Acest protocol tratează controlul fluxului, astfel încât un emițător rapid nu inundă un receptor lent cu mai multe mesaje decât poate acesta să prelucreze.

UDP( User Datagram Protocol – protocolul datagramelor utilizator) este un protocol care nu este bazat pe conexinui, nesigur, ceea ce înseamnă ca pachetele nu ajung întotdeauna la destinație. Este folosit pentru întrebările scurte adresate de către client serverului și în aplicațiile în care comunicarea rapidă este mai importantă decât comunicarea cu precizie. Astfel de exemple sunt aplicațiile de transmisie a filmelor și a vorbirii. În figura de mai jos este prezentată relația dintre protocoalele IP, TCP și UDP.

Nivelul Aplicație

Acest nivel se află deasupra nivelului Transport. Conține toate protocoalele de nivel

înalt prezente și în figura de mai sus. Protocolul de terminal virtual (TELNET) permite unei mașini de a se conecta la altă mașină aflată la distanță și permite utilizatorului de a lucra pe această mașină. FTP sau protocolul de transfer de fișiere, permite mutarea datelor de pe o mașină pe alta în mod eficient. SMTP sau Simple Mail Transfer Protocol a fost la început doar un tip de transfer de fișiere, dar apoi a fost dezvoltat un protocol specializat pentru serviciul de e-mail.

În timp, la aceste protocoale s-au adăugat și altele precum DNS(Domain Name Service) pentru stabilirea corespondeței dintre numele gazdelor și adresele rețelelor, HTTP (Hypertext Transfer Protocol) folosit pentru navigarea pe internet și multe alte protocoale.

Nivelul Gazdă la rețea

Se ocupă cu toate problemele legate de transmiterea efectivă a unui pachet IP pe o legătură fizică, incluzând și aspectele legate de tehnologii și de medii de transmisie, adică nivelurile OSI Legătură de date și Fizic.

Comparție între modelul OSI și modelul TCP/IP

Aceste două modele, modelul OSI și modelul TCP, au multe lucruri în comun. Amândouă au protocoale care funcționează independent, iar funcționalitatea nivelurilor este în mare parte similară. Spre exemplu, nivelurile Fizic, Legătură de date și Transport, sunt necesare pentru comunicarea proceselor, acestea punând la dispoziție un serviciu de transport cap la cap independent de rețea. Aceste niveluri formează furnizorul de transport.

Între cele două modele există și deosebiri. Comparația se face între modelele de referință, și nu între stivele de protocoale. Modelul OSI are trei concepte esențiale: servicii, interfețe și protocoale.

Fiecare nivel oferă servicii nivelului aflat deasupra sa. Definiția serviciului spune ce face nivelul, nu cum funcționează acesta sau cum folosesc entitățile de deasupra sa, serviciul respectiv. Interfața unui nivel informează procesele superioare cum este accesat nivelul. Intefața precizează rezultatul care se obține și ce reprezintă fiecare parametru.

Interfațele sau serviciile nu dau detalii despre funcționarea internă a nivelului. Protocoalele folosite într-un nivel dau informații despre cum funcționează anumite servicii din acest nivel. Nivelul poate folosi orice protocol, cu condiția ca acesta să funcționeze. Nivelul poate modifica protocoalele fără ca acest lucru să afecteze nivelurile superioare.

Putem să facem o comparație cu programarea orientată pe obiect. Un obiect , ca și un nivel, are un set de operații (metode) care pot fi apelate de către procesele din afara obiectului. Parametrii și rezultatele operațiilor, formează interfața obiectului.Codul intern al obiectului reprezintă protocolul său și nu este vizibil în afara acestuia.

Spre deosebire de modelul OSI, modelul TCP nu face o distinge clar serviciul, interfața și protocolul. Singurele servicii oferite sunt SENDIP PACKET și RECEIVEIP PACKET. În consecință protocoalele modelului OSI, sunt mai transparente decât cele din modelul TCP/IP și pot fi schimbate într-un mod rapid odată cu avansarea tehnologiei. Capacitatea de a face astfel de modificări este unul din obiectivele principare ale organizării pe niveluri în nivelul OSI.

Tehnologii utilizate

Modelul Client – Server

Serverul este o mașină care asigură resurse și servicii pentru client. Orice calculator de la care pot fi cerute resurse se numește server. Sistemele Client/Server au în esență următorul lucru: Clientul cere de la server resurse și informații. O mașină se poate comporta în același timp și ca un server și ca un client. Cea mai bună definiție a unui server este data de rețelele locale(LAN), serverul fiind o mașină puternică ce stochează toate fișierele și aplicațiile.Celelalte calculatoare din rețea se conectează pentru a avea acces la fișiere. În rețelele locale de obicei o singură mașină se comportă ca server, restul fiind clienți.

Pot exista mai multe server într-o rețea mare. Unul se poate ocupa de fișierele pentru rețea (server de fișiere), unul de cererile de tipărire, altul de conexiunile cu rețelele exterioare (server de comunicație), și altele. Pot exista unul sau mai multe servere de același tip.

Clientul reprezintă o mașină care trimite cereri către server. Într-o altă definiție a clientului, serveru poate furniza putere de calcul către mașinișe mai mici conectate la el.

O rețea locala de 20 de mașini poate avea un server mare să țină fișierele, bazele de date, iar restul mașinilor să se conecteze fiecare ca un client.

Familia de protocoale TCP/IP

Acronimul TCP vine de la „Transmission Control Protocol”, iar IP de la „Internet Protocol”. Amândouă formează scheletul aplicațiilor online: navigarea pe internet, mesageria instantă, serviciul de e-mail.

TCP/IP reprezintă un pachet de protocoale de rețea. Protocoalele sunt reguli pe care programele sofware nu trebuie să le încalce, pentru a face posibilă comunicarea între ele.

Un protocol definește modul în care fiecare mașină are grijă de transferul de informații. El reprezintă un set de reguli care definește modul în care două mașini comunică între ele, fiecare conformându-se cu aceleași standarde. TCP/IP este protocolul de rețea cel mai mult folosit în lume, atât pentru rețele mari cât și pentru rețele mici.

TCP/IP se referă la o familie de protocoale, dezvoltate pentru transferul de informații prin intermediul rețelei. Părțile protocolului TCP/IP au diferite obiective, spre exemplu serviciul de e-mail, transferul de fișiere, serviciul de autentificare la distanță sau dirijarea de mesaje.

Serviciile protocolului TCP/IP și funcțiile lor sunt grupate după obiectivul lor. Protocoalele de transport controlează datele dintre două mașini și include:

TCP (Transmision Control Protocol) reprezintă un serviciu bazat pe conexiuni,

ceea ce înseamnă cǎ mașinile comunică una cu cealaltă sunt conectate.

UDP (User Datagram Protocol) este un serviciu fǎrǎ conexiuni, adică

datele sunt trimise fǎrǎ ca mașinil sǎ fie conectate. O analogie din viața reală ar fi trimiterea unei scrisori prin poșta normală, la o adresă anume, fără să știm daca va ajunge sau nu la acea adresă.

Protocoalele de rutare determină calea cea mai rapidă către destinație. Se pot ocupa și de împățirea mesajelor mari și recombinarea acestora la destinație:

IP(Internet Protocol) realizează transmiterea datelor.

ICMP(Internet Control Message protocol) se ocupă de erorile și schimbările în hardware-ul rețelei ce afectează dirijarea mesajelor.

RIP(Routing Information Protocol) este unul din protocoalele care determină cea mai bună metodă de dirijare pentru livrarea mesajelor.

OSPF(Open Shortest Path First) este un alt protocol de rutare.

Protocoalele de adresa(Network Address) sunt protocoalele care le atriubie mașinilor câte un nume și câte un număr unic, și se ocupă de felul în care acestea sunt adresate.

ARP(Address Resolution Protocol) se ocupă cu aflarea adreselor unice ale mașinilor din rețea

DNS(Domain Name System) află adresele numerice pornind de la numele unei mașini.

RARP(Reverse Address Resolucion Protocol) află adresele unice ale mașinilor din rețea dar operează invers față de ARP.

Serviciile utilizator reprezintă aplicații pe care o mașină le poate folosi:

BOOTP(Boot Protocol) pornește o mașină din rețea cu informația de bootare de la un server.

FTP(File Transfer Protocol) Transferă fișiere de la o mașină la alta.

TELNET este protocolul care permite autentificări la distanță, adică un utilizator se poate conecta de pe mașina proprie la o altă mașină din rețea, având acces la mouseul și tastatura acesteia.

Următoarele protocoale nu se gasesc în cele menționate mai sus, dar sunt importante într-o rețea:

NFS(Network File System) permite ca folderele de pe altă mașină să fie accesate de un utilizator ca și cum ar fi locale.

NIS(Network Information Service) simplifică menținere conturilor și parolelor ale utiizatorului.

RPC(Remote Procedure Call) permite comunicarea la distanță într-o manieră simplă

SMTP(Simple Mail Transfer Protocol) este un protocol care transferă e-maiuluri între mașini.

SNMP(Simple Network Management Protocol) este un serviciu care trimite mesaje despre starea rețelei li dispozitivele atașate, administratorilor.

Comparație între protocoalele TCP și UDP

TCP asigură siguranța și ordinea livrării a pachetelor de la utilizator la server sau vice versa. UDP nu este bazat pe conexiuni și nu se verifică dacă mașina destinație este pregătită pentru a primi un nou pachet.

\

Siguranța pachetelor

TCP este mult mai sigur deoarece gestionează mesaje de confirmare și retransmisia datelor în cazul pachetelor pierdute. Nu se va pierde niciun pachet. UDP nu gestionează astfel de mesaje de confirmare și retransmisia pachetelor nu este disponibilă.

Ordinea pachetelor

Pachetele sunt trimise într-o ordine prin TCP și sunt recepționate în aceeași ordine. În cazul în care pachetele sunt în altă ordine, TCP reordonează pachetele și le livrează. UDP transmite mesajele într-o ordine care poate să nu corespundă cu ordinea în care acestea sunt recepționate. Nu există nicio cale de a prezice ordinea în care mesajele vor ajunge la destinație.

Comparație între protocoalele IPv4 și IPv6

Detalii de implementare

Aplicația a fost dezvoltată în limbajul C. Deoarece se bazează pe modelul client-server am creat doua fișiere, câte unul pentru fiecare entitate. De asemenea am mai folosit și un fișier comun celor doua entități cu funcții care sunt folosite și de client și de către server. Un exemplu ar fi adăugarea de noi utilizatori. Atunci când clientul se comportă ca și server, va folosi aceeași funcție de adăugare a utilizatorilor în program, pe care o folosește și serverul principal.

Setarea serverului

Pentru a pregăti acceptarea de mesaje atât pe client cât și pe server, am creat, în fișierul comun al celor două entități, o funcție numită „setup_server”. Această funcție primește ca parametru portul pe care o să fie setat serverul.

Setarea serverului presupune crearea unui socket TCP și pregătirea acestuia de a accepta mesaje. Crearea socketului se face cu functia „socket”. Funcția primește trei parametrii. Primul parametru ne indică protocolul de IP folosit pentru conexiune(IPv4 sau IPv6), al doilea parametru reprezintă tipul socketului TCP sau UDP, iar cel de-al treilea parametru se setează la valoarea „0” implicit. În aplicație am folosit sockeți de tip TCP și protocolul de ip IPv4(reprezentat pe 4 bytes). Pentru aceste setări am folosit funcția „socket” cu primul parametru setat cu valoarea „AF_INET” iar cel de-al doilea parametru cu valoarea „SOCK_STREAM”. Dacă funcția „socket” este executată cu succes, se returnează file descriptorul aferent socketului. În caz contrar se returnează valoarea „-1”.

După crearea socketului, acestuia trebuie sa îi asignăm o adresă. Acest lucru se face cu funcția „bind”. Această funcție primește tot trei parametrii: primul fiind socket file descriptorul returnat de funcția „socket” apelată anterior, al doilea reprezintă o structură care setează tipurile de IP acceptate de socket, iar al treilea parametru reprezintă dimensiunea acestei structuri. Structura se declară de tipul „sockaddr_in” și trebuie completate trei câmpuri ale ei. Câmpul „sin_family” reprezintă tipul de socket folosit, in acest caz TCP, câmpul „sin_port” reprezintă portul pe care îl asignăm socketului, și ultimul câmp informează socketul ce tip de adrese să accepte. Acest ultim câmp este setat la valoarea „INADDR_ANY” pentru a accepta orice adresă IP. Dacă funcția se execută cu succes se returnează valoarea „0”, altfel se returnează valoarea „-1” și pe ecran va fi afișat mesajul de eroare.

Funcția „listen” marchează socketul primit ca parametru ca fiind gata pentru a primi noi mesaje, unele dintre mesaje semnificând o cerere de conexiune. Funcția primește ca parametru și numărul maxim de conexiuni pe care serverul le poate avea în același timp.

Funcția „setup_server” creată pentru a folosi atât serverului cât și clientului, va returna socketul creat și pregătit pentru a accepta mesaje.

Conectarea clienților

Inițial serverul poate primi mesaje doar pe doi sockeți, aceștia fiind, socketul care l-am pregătit mai devreme și socket file descriptorul STDIN, care reprezintă inputul de la tastatură.

Pentru a accepta conexiuni de la clienți, serverul răspunde cu funcția „accept” mesajelor care reprezintă o cerere de conexiune. Funcția primește trei parametrii: primul reprezintă socketul pe care este recepționat mesajul, al doilea reprezintă o structură care se va completa automat cu datele clientului(adresa IP și portul clientului), iar al treilea parametru reprezintă dimensiunea structurii. Funcția „accept” returnează în caz de succes un nou socket care va reprezenta punctul de legătură dintre server și client. Serverul va primi mesaje de la client pe acest socket. Fiecare client în parte are câte un socket file descriptor. În caz de eroare, funcția va returna valoarea „-1”.

Se creează o listă unde se adaugă toți clienții care sunt conectați la server. Adăugarea se face prin funcția „add_client”, care primește cinci parametrii. Primul parametru este socketul tocmai creat de funcția „accept”, al doilea parametru reprezintă lista de clienți unde va fi adaugat cel pentru care este apalată funcția, al treilea parametru reprezintă numarul de clienți conectați până în acel moment, al patrulea parametru este reprezentat de un pachet care conține datele clientului(nume, port, data de conectare), iar ultimul parametru este strutura care a reținut în funcția „accept” adresa IP a clientului. Această adresă va fi decriptată in funcția de adăugare a clientului.

Lista de clienți care este trimisă ca parametru reprezintă o strutură de date definită astfel:

Variabila „nume” reprezintă numele clientului, variabila „ip[4]” reprezintă adresa IP a clientului. Această adresă va fi reținută sub forma unui vector. „port” va reprezenta portul clientului, „clientfd” este socket file descriptorul returnat de funcția „accept”, iar „start_date” reprezintă data de conectare a clientului.

În funcția de adăugare client se creează un pachet care va fi trimis clientului ce a făcut cererea de conexiune. Acest pachet va conține următoarele informații: Un mesaj de întâmpinare, sau în cazul în care un client cu același nume există deja, acest pachet va înștiința clientul care vrea să se conecteze că numele este deja folosit. Un pachet are urmatoarea structură:

Variabila „type” reprezintă tipul comenzii pe care clientul o trimite către server.Această variabilă poate lua valori următoarele valori: 1-7 sunt valori care reprezintă tipul comenzii pe care clientul le poate trimite serverului, 0 este valoarea prin care un client trimite datele pentru a se conecta la server, -1 și -2 sunt valori pentru a înștiința clientul daca un utilizator cu același nume există deja sau dacă fișierul pe care vrea sa îl partajeze este sau nu partajat. Variabila „payload” reprezintă datele care sunt transmise între client și server. Constanta „SIZE” este definiă cu valoarea de 4096 biți.

Serverul primește datele despre client printr-un pachet folosind funcția „recv”. Această funcșie primește patru parametrii: primul parametru reprezintă socketul creat în urma funcției „accept”, al doilea parametru reprezintă pachetul unde vor fi memorate datele, al treilea parametru este reprezentat de dimensiunea pachetului și ultimul parametru este setat „0” implicit.

Pentru a verifica dacă numele este deja folosit, se parcurge lista de clienți și se va compara fiecare nume cu cel care vrea să se conecteze folosind funcția „strcmp”. Această funcție primește ca parametru două variabile de tip „string”, iar dacă aceste variabile sunt identice, funcția va returna valoarea 0.

Dacă numele nu este folosit, se vor seta următoarele: numele, portul,adresa IP, data conectării și socket file descriptorul clientului și va fi adaugat în listă la sfârșit. Pentru a seta adresa IP, aceasta trebuie mai întâi decriptată. Decriptarea se face cu funcția „inet_ntoa” care returna adresa IP sub forma unui „string” (Ex: 127.0.0.1).

Această adresă trebuie parsată pentru a o memora sub forma unui vector de 4 biți. Se folosește funcția „strtok” care va primii doi parametrii de tip „string”: adresa IP și un delimitator. Funcția va returna datele până la delimitator sub forma unui „string”. Asta înseamnă că va fi returnat doar „127” din exemplul nostru. pentru restul valorilor funcția mai trebuie apelata de încă trei ori. Acest apel se face într-un „while” care se va opri atunci cand rezultatul funcției va fi „null”. Cât timp rezultatul este diferit de „null” vom completa adresa IP a clientului.

Variabila „type” din pachetul care este creat pentru a înștiința clientul daca un nume identic există deja în lista de utilizatori va primii valoarea „-2” la inceput, semnificând faptul că numele este disponibil. După verificarea întregii liste de clienți, această variabilă poate primii valoare „-1” în cazul în care numele este deja folosit.

Dacă numele cu care clientul încearcă să se conecteze există deja, serverul îi va trimite un mesaj folosind funcția „send” care primește patru parametrii la fel ca „recv”. Primul parametru este socketul pe care serverul trimite mesajul, și acesta este socketul creat în urma funcției „accept”, al doilea parametru reprezintă pachetul creat pentru a înștiința clientul că numele există deja, al treilea parametru este dimensiunea pachetului, iar ultimul parametru este setat 0 implicit. Dupa trimiterea mesajului serverul închide conexiunea cu acest client prin funcția „close”.

În cazul în care numele este disponibil, clientul va primi un mesaj de confirmare. La consola clientului se va afișa mesajul „Bine ai venit!”.

Din perspectiva clientului, conectarea se face la server folosind funcția „connect_client” definită de programator. Această funcție primește trei parametrii: primul parametru reprezintă socketul creat pentru a crea o conexiune cu serverul, al doilea parametru este portul pe care serverul acceptă mesaje, iar al treilea parametru reprezintă adresa IP a serverului. Funcția va returna „0” în cazul în care s-a executat cu succes.

Funcția „connect_client” setează datele pentru conexiune și apelează o alta funcție numită „connect”. Datele pentru conexiune se referă la portul pe care serverul primește mesaje, adresa IP și tipul socketului, în acest caz TCP. Această rutină a fost creată pentru a reduce numarul liniilor de cod scrise și pentru o utilizare mai ușoară în program.

În cazul în care conexiunea a avut loc, clientul trimite un pachet serverului cu datele sale(nume, port, data conectării). Acest pachet este trimis cu funcția „send”. Clientul așteaptă răspuns de la server. Dacă numele există deja, programul client se încheie folosind comanda „exit”, altfel se afișează la consolă mesajul de întâmpinare și se pregătește un nou socket pentru client. Acest socket este setat pentru a accepta cereri de conexiune folosind aceeași funcție ca și pentru server, „setup_server”.

Multiplexarea comunicației

După ce s-au conectat mai mulți clienți, serverul trebuie să verifice și sockeții noi creați pentru mesaje. Acest lucru se face într-o buclă infinită folosind funcția „select”. Funcția permite programului să monitorizeze mai multi file descriptori, așteptând până unul sau mai multi devin pregătiți pentru operații de citire sau scriere. Un file descriptor este considerat pregătit daca este posibil să se facă o operație de citire sau scriere pe el fără erori. Funcția select primește ca parametru totți file descriptorii care pe care se pot face operații de citire(readfds), toți file descriptorii pe care se pot face operații de scriere(writefds), toți file descriptorii care reprezintă o excepție, valoarea maximă dintre toți file descriptorii și limita de timp în care funcția rămâne blocată.

Pentru setarea maximului și adăugarea tuturor file descriptorilor în variabilele „readfds”, respectiv „writefds”, care reprezintă file descriptorii pentru citire și pentru scriere, am creat o funcție numită „setup_fds”. Funcția va returna valoarea maximă dintre toți file descriptorii.

La apelarea funcției se vor reseta variabilele „readfds” și „writefds” folosind funcția „FD_ZERO”. Acest lucru se întâmplă deoarece funcția fiind într-o buclă infinită, se reapelează de fiecare dată, și unii file descriptori pot sa nu mai existe(Ex: un client se deconectează de la server). După resetarea variabilelor, se vor adăuga socket file descriptorii rămași. Adăugarea se face cu funcția „FD_SET”.

Socket file descriptorii care pot fi adaugați în „readfds” sunt:

Socket file descriptorul serverului care primește cereri de conexiune(acesta poate să fie cel de pe client atunci când se comportă ca server sau cel de pe serverul principal).

Socket file descriptorii clienților conectați

Socket file descriptorii fișierelor care sunt în curs de descărcare(aceștia se vor adăuga doar pe clientul care primește date).

Socket file descriptorul pentru citirea de la tastatura „STDIN”.

Socket file descriptorii care pot fi adaugați în „writefds” sunt:

Socket file descriptorii fișierelor care sunt în curs de descărcare(aceștia se vor adăuga doar pe clientul care trimite date).

După apelarea funcției „select”, se vor parcurge pe rând file descriptorii rămași în „readfds” și „writefds”, se va accepta mesajul de pe fiecare, iar serverul îl va prelucra. Verificarea file descriptorilor se face cu funcția „FD_ISSET”. Dacă pe socket file descriptorii clienților avem mesaje, acestea vor fi prelucrate în ordinea recepționării. Mesajele care vin pe socket file descriptorii clienților reprezintă comenzi ale clienților date serverului.

Implementarea comenzilor client

Aplicația are în funcționalitatea ei opt comenzi pentru client și două comenzi pentru server.

Toate comenzile sunt date de la tastatură. Pentru comunicarea între server și client am folosit o structură de forma :

Comenzile clientului sunt:

1. listclients

Utilizatorii pot cere serverului lista cu toți clienții conectați. Pentru acest lucru ei trebuie sa trimită de la tastatură comanda „listclients”.

Comanda primește ca parametru socket file descriptoru care va face conexiunea cu serverul pentru a comunica cu acesta. Se setează câmpul „type” din pachetul care va fi trimis către server la valoarea „1”. Acest câmp informează serverul să prelucreze comanda „listclients”.

Clientul trimite folosind funcția „send” acest pachet pe socketul trimis ca parametru.

Serverul recepționează pachetul folosind funcția „recv” și apelează funcția „listclients” care va oferi datele cerute de către client. Funcția „listclients” din server primește trei parametrii: socketul care face conexiunea cu clientul, lista de clienți și numarul clienților conectați. Funcția creează la rândul ei un alt pachet care va fi completat cu numele tuturor clienților. Completarea se face parcurgând lista de clinți și adăugând numele fiecăruia separat de spațiu. Adăugarea am facut-o cu funcția de concatenare „strcat”. „Pachetul” completat se trimite clientului.

Clientul recepționează pachetul și separă numele din pachet folosind funcția „strtok”. Numele fiecărui client este afișat la consolă.

2. infoclient nume_client

Clienții pot cere informații despre alți clienți conectați folosind aceasă comandă.

Funcția „infoclient” prelucrează stringul oferit ca parametru de la tastatură, acesta reprezentând numele clientului despre care se cer informații. Se creează un pachet, iar variabila „type” a acestuia va fi inițializată cu valoarea „2”, valoare ce reprezintă comanda „infoclient”. Dacă numele oferit de la tastatură este „null”, funcția își va încheia execuția, iar la consolă se va afișa mesajul „Nume invalid!”.

Dacă numele este valid, acesta se va copia în pachetul creat și va fi trimis către server prin funcția „send”. Serverul recepționează mesajul prin funcția „recv” și apelează funcția „infoclient”. Funcția de pe server primește ca parametru socketul care face conexiunea cu clientul, lista de clienți, numarul clienților și pachetul primit de la client. Funcția creeaza la rândul ei un alt pachet care va fi trimis înapoi la client. Acest pachet va conține informațiile cerute.

Pentru a completa acest pachet, se parcurge lista de clienți și se verifică numele fiecărui client cu numele primit de la cel care a facut cerera. În cazul în care cautarea a avut succes, datele clientului vor fi adăugate în pachet folosind funcția „sprintf”, funcție care scrie într-un șir de caractere.

„Pachetul” este trimis clientului. El va verifica conținutul acestuia și în cazul în care conținutul este gol, pe ecran va fi afișat mesajul „Clientul nu există!”, deci clientul despre care s-a cerut informații nu a fost găsit în lista de clienți conectați. Dacă pachetul nu este gol, se vor afișa datele clientului astfel: Datele sunt extrase din pachet folosind funcția „strtok”, numele este afișat așa cum este extras, portul este convertit la tipul de date „int” folosind funcția „atoi” și apoi este afișat, iar timpul care a trecut de la conectarea clientului este calculat ca o diferență între data la care se execută comanda și data la care clientul s-a conectat.

3. message nume_client mesaj

Clienții pot comunica între ei prin mesaje text trimise cu comanda „message”. Parametrii care se dau de la tastatura sunt numele clientului căruia îi este transmis mesajul și mesajul propriu-zis.

Inițial clientul care vrea să trimită mesajul, cere informații serverului despre clientul cu care vrea să comunice. Serverul îi trimite datele de conexiune ale clientului. Transmiterea de mesaje se face printr-o conexiunea client-client, mesajul neajungând la server. Modelul este prezentat în figura următoare:

Clientul care vrea sa trimită mesajul va crea un nou pachet pe care îl va completa cu mesajul propriu-zis. Pentru a trimite și mesaje care conțin caracterul „spatiu”, se folosește următorul algoritm: Se extrage fiecare cuvânt din mesajul trimis de la tastatură folosind funcția „strtok”, funcție care este executată într-o buclă infinită până ce rezultatul ei va fi „null”, și se creează un mesaj care concatenează aceste cuvinte separate de câte un „spațiu”. Adăugarea și concatenarea cuvintelor se face cu funcția „strcat”.

Clientul care vrea sa trimită mesajul, va creea un nou socket care va comunica direct cu clientul care va primi mesajul. Se creează un pachet iar variabila „type” este setată la valoarea „3”, reprezentând comanda „message”. pachetul se va completa cu numele clientului căruia îi este adresa mesajul, și se trimite către server folosind funcția „send”.

Funcția „message” din server primește ca parametru lista ce clienți conectați, numarul acestora și pachetul primit de la client. Serverul va parcurge lista clienților conectați, și va compara numele fiecăruia cu numele primit de la client. În cazul în care căutarea a avut succes, se vor scrie într-un pachet nou creat, datele de conectare ale clientului găsit. Datele de conectare sunt portul și adresa IP, și se vor scrie în pachet folosind funcția „sprintf”. Pentru a nu continua căutarea după ce un client a fost găsit vom pune un „break” după scrierea datelor în pachet. „break”-ul are rolul de a întrerupe bucla de căutare. „pachetul” cu datele de conectare sunt trimise la client.

După primirea pachetului de la server, clientul va folosi funcția „connect_client” cu datele recepționate, și se va conecta la clientul căruia vrea sa-i transmită mesajul. În pachetul care va fi trimis, va fi trimis și numele clientuluicare a trimis mesajul.

Dacă pachetul primit de la server este gol, se va afișa la consolă mesajul „Clientul nu există!”, iar dacă numele care este dat ca parametru este identic cu cel care a trimis mesajul, se va afișa „Nu îți poți trimite singur mesaje!”.

Pentru acceptarea mesajului am creat o funcție numită „accept_message”. Această funcție primește ca parametru mesajul recepționat de la clientul care l-a trimis, și îl afișează la consolă în următorul format: „Nume: Mesaj”. După recepționarea mesejului conexiunea este închisă.

4. sharefile nume_fișier

Pentru a partaja un fișier, clientul folosește comanda „sharefile”.Această comandă primește un parametru de la tastatură care reprezintă numele fișierului pe care clientul dorește să îl partajeze.

În programul client, funcția creată pentru a partaja un fișier se numește tot „sharefile”, însă această funcție primește trei cinci parametrii. Primul parametru este socketul prin care este conectat la server, al doilea parametru este clientul care trimite comanda ( acest parametru are rolul de a memora în lista de fișiere partajate pe server, și numele clientului care l-a partajat), al treilea parametru este o listă memorată în programul client, care reprezintă fișierele partajate de acesta, al cincilea parametru este reprezentat de numărul acestor fișiere, iar ultimul parametru poate să fie „1” sau „0”(în cazul în care este 1, comanda este folosită pentru a partaja un fișier, altfel este folosită pentru a șterge un fișier din lista celor partajate).

Se crează un pachet care va fi trimis la server, setând variabila „type” la valoarea „4” dacă folosim funcția pentru a partaja un fișier, sau la valoarea „5” pentru a renunța la un fișier partajat.

Se verifică mai întâi dacă fișierul există, în caz contrar se afișează la consolă mesajul „Fișierul nu există!”. Dacă fișierul există se completează „packetul” creat cu numele clientului urmat de numele fișierului și se trimite către server folosind funcția „send”.

Serverul, spre deosebire de client, are definit doua funcții, una pentru partajarea fișierelor și una pentru departajarea acestora. Funcția de partajare „sharefile” din server, primește ca parametru socketul care comunică cu clientul, lista fișierelor partajate de către toți clienții, numarul acestora și pachetul primit de la client.

În server se va crea un pachet căruia i se va seta variabila „type” la valoarea „-2”, aceasta reprezentând că fișierul nu este încă partajat.

Funcția extrage numele clientului și fișierul folosind funcția „strtok”, apoi parcurge lista de fișiere partajate pentru a verifica daca o înregistrare cu același nume și același fișier există deja. Parcurgerea se face folosind o instrucțiune „for”. Dacă este gasită o înregistrare cu același nume și același fișier, variabila „type” din „pachetul” nou creat va lua valoarea „-1” și se va trimite acest pachet către client. Se apelează „return” și funcția își încheie execuția. Dacă nu este gasită nicio înregistrare, se trimite pachetul la client cu variabila „type” având valoarea „-2” și se adaugă în lista fișierelor partajate noul fișier.

Clientul verifică variabila „type” din pachetul primit, iar dacă aceasta este „-1” va afișa la consolă mesajul „Fișierul este deja partajat!”, altfel, dacă este „-2” va adăuga fișierul în lista fișierelor partajate de el și va afișa pe ecran mesaju „Fișier adăugat cu succes!”.

Pentru lista de fișiere partajate am creat un nou tip de date numit „sharefiles”: Structura lui este următoarea:

Variabila „nume” reprezintă numele clientului, iar variabila „fisier” va reprezenta fișierul care este partajat. Fișierul este memorat cu tot cu calea acestuia, nu doar numele.

5. unsharefile nume_fișier

Comanda „unsharefile” este folosită pentru a scoate un fișier din lista fișierelor partajate. Va primi ca parametru numele fișierului. De această dată variabia „type” din pachetul care îi este trimis serverului se va seta la valoarea „5”, reprezentând comanda „unsharefile”.

Pachetul este trimis către server, unde se va apela funcția „unsharefile”. Funcția, la fel ca și în cazul precedent la „sharefile”, va extrage numele clientului și numele fișierului din pachetul primit și îi va cauta în lista de fișiere partajate. Dacă există o înregistrare care are același nume și același fișier cu cele primite de la client, această înregistrare se va șterge, și se va trimite un pachet de confirmare setând variabila „type” a acestuia la valoarea „-2”.

Dacă nu există nicio înregistrare în lista de fișiere partajate care să corespundă cu datele primite de la client, se va seta variabila „type” la valoarea „-1”. Pachetul este trimis la client, iar acesta va verifica variabila „type”. Dacă variabila „type” are valoarea „-2” va șterge din lista de fișiere partajate fișierul respectiv iar la consolă se va afișa mesajul „Fișierul a fost șters cu succes!”, altfel, dacă valoarea este „-1” la consolă va fi afișat mesajul „Fișierul nu este partajat!”.

6. getshare nume_client

Clientul are posibilitatea de a vedea ce fișiere au partajate ceilalți clienți conectați la server. Acest lucru se face cu comanda „getshare” urmată de numele clientului căruia vrem să îi vedem fișierele partajate.

Clientul va face o cerere către server, iar va răspunde și va trimite înapoi lista fișierelor partajate de clientul dat ca parametru. Se creează un pachet care va reprezenta tipul comenzii, iar pentru asta se setează variabila „type” la valoarea „6”. Se extrage numele clientului din comanda trimisă de la tastatură iar dacă acesta nu există se va afișa pe ecran mesajul „Lipsește numele!”.

Dacă numele există se trimite la server pachetul completat cu numărul comenzii și cu numele clientului. Serverul creează la rândul său un pachet pe care îl va completa cu fișierele partajate. Acest lucru se face parcugând lista de fișiere partajate folosind instrucțiunea „for”, și în cazul în care numele primit de la client corespunde cu numele clientului din listă se va adăuga în pachetul creat pe server. Fișierele vor fi separate de caracterul „;”. Pachetul este trimis către client.

După primirea pachetului clientul verifică dacă acesta este gol, caz în care va afișa la consolă mesajul „Clientul nu are niciun fișier partajat!”, altfel va extrage fișierele folosind funcția „strtok” și le va afișa la consolă câte unul pe fiecare linie.

Pe server, fișierele sunt memorate folosind întreaga sa cale(Ex: C:/Data/Filme/this.avi). Clientul va primii aceste fișiere separate prin „;”, dar va extrage doar numele fișierului lăsând restul deoparte. Folosind funcția „basename” primind ca parametru întreaga cale, aceasta va returna doar numele fișierului(Ex: this.avi). Fișierele afișate la consola clientului nu vor conține întreaga cale.

7. getfile nume_fișier

Această comandă reprezintă subiectul principal al acestei lucrări. Executând această comandă fișierul va fi descărcat în calculatorul clientului. Se trimite de la tastatura numele numele fișierului care se va descărca.

Ca și în cazul trimiterii mesajelor, pentru a descărca un fișier, clientul cere de la server date despre clientul care are fișierul, iar transferul se va face independent de server, printr-o conexiune client-client. Serverul doar va furniza datele de contact.

Se va creea un „pachet” cu tipul comenzii, variabila „type” având valoarea „7”. Se trimite la server pachetul cu numele fișierului. Serverul creează un pachet și va folosi variabila „type” a acestuia pentru a confirma dacă fișierul a fost sau nu găsit. Această variabilă va avea inițial valoarea „-2”, iar dacă se va găsi fișierul trimis de client în lista fișierelor partajate variabila va lua valoarea „-1”.

Dacă fișierul a fost găsit se va completa „pachetul” creat pe server, cu numele , portul și adresa IP a clientului. pachetul va fi trimis către client. Acesta verifică variabila „type” pentru a vedea dacă fișierul este sau nu partajat. Dacă nu este partajat, la consolă se va afișa mesajul „Fișierul nu este partajat!”, altfel se creează o conexiune între clientul care a dat comanda și cel care are fișierul partajat folosind funcția „connect_client”.

Fișierele în curs de descărcare sunt salvate într-o listă de fișiere care au următoarea structură:

Variabila „f” reprezintă file descriptorul pentru fișierul care va fi copiat. „client_name” este numele clientului de unde se va copia fișierul, „file_name” este numele fișierului în curs de descărcare, „full_path” este numele fișierului cu tot cu calea acestuia. „fd” este socket file descriptorul care face conexiunea prin care se trimite fișierul. Variabila „file_size” reprezintă dimensiunea totală a fișierului, iar variabila „file_sent_size” reprezintă ce dimensiune din fișier a fost trimisă până în acel moment. Aceasta din urma se modifică la fiecare recepționare de pachet din fișier.

Se presupune că avem clientul 1 care vrea sa descarce un fișier, și clientul 2 care are acest fișier. Clientul 1 va creea un fișier folosind funcția „fopen” pentru a scrie în el datele primite de la clientul 2 . După conectare, clientul 1 va trimite un „pachet” către clientul 2, având variabila „type” setată la valoarea „7”. Clientul 2 verifică variabila „type” a pachetului, pentru că este posibil sa fie doar un mesaj, nu o cerere de descărcare, și apelează funcția „set_download”.

Această funcție primește sase parametrii. Primul parametru reprezintă socket file descriptorul care a fost creat în urma conexiunii dintre cei doi clienți, al doilea parametru reprezintă lista de fișiere care sunt în curs de trimitere, iar al treilea parametru este numărul acestor fișiere. Al patrulea parametru este pachetul primit de la clientul 1, al cincilea parametru reprezintă lista de fișiere partajate, iar ultimul parametru numărul acestora.

Funcția verifică dacă fișierul este deja în curs de trimitere, și în acest caz va opri execuția ei, trmițându-i clientului 1, un pachet de informare.

Dacă fișierul nu este în curs de trimitere, se va adăuga în lista fișierelor în curs de trimitere, și se va deschide fișierul în modul „rb”(citire binară). Pentru a afla dimensiunea totală a fișierului, cursorul este mutat la sfârșit folosind funcția „fseek”. Această funcție primește trei parametrii: primul reprezintă file descriptorul asociat fișierului, al doilea numarul de biți deplasați, și al treilea poziția de unde se deplasează biții. În cazul nostru funcția se va apela „fsee(f,0,SEEK_END)”, adică vom muta cursorul cu 0 biți de la sfârșitul fișierului.

După mutarea cursorului, vom apela funcția „ftell” care va primii ca parametru descriptorul fișierului și va returna poziția actuală din fișier, poziție ce reprezintă dimensiunea fișierului în biți. Variabila „file_size” va lua valoarea „ftell(f)”, iar variabila „file_sent_size” este setată la 0. Cursorul este setat la începul fișierului folosind funcția „fseek(f,0,SEEK_SET)”și fișierul este gata de citire.

Socket file descriptorii fișierelor care se trimit se vor adăuga în „writefds” pentru a vedea dacă vreunul din ele nu s-a transferat complet. Socket file descriptorii fișierelor care se descarcă se vor adăuga în „readfds” pentru a vedea dacă încă mai primesc „pachete”.

Dacă dupa apelul funcției „select” există vreun socket file descriptor în „writefds” se va apela funcția „send_file”. Dacă există vreun socket file descriptor în „readfds” se apelează funcția „accept_file”.

Funcția „send_file” va primi ca parametru lista de fișiere partajate de clientul care o apelează, numarul fișierelor și o variabilă „i” care reprezintă indexul fișierului care se trimite.

Se verifică dacă dimensiunea datelor care au fost trimise este mai mică decât dimensiunea totală a fișierului, și în acest caz se trimite o nouă bucată din fișier. Citirea din fișier se face cu funcția „fread” care primește ca parametru „pachetul” care este trimis, tipul de date pe care îl citește, numărul de blocuri pe care îl citește și file descriptorul. În cazul nostru numărul de blocuri pe care funcția îl citește este de 1024, iar tipul de date pe care îl citește este „char”. Între trimterea acestor blocuri de 1024 de bytes, clientul este capabil de a executa și alte comenzi date de la tastatură.

Variabila „type” este setată la valoarea returnată de funcția „fread” pentru a informa clientul de la celălalt capăt cați biți au fost trimiși. În cazul în care fișierul nu are o dimensiune care se divide cu 1024 de bytes, trebuie să știe cați biți va prelua din pachetul primit. Se adaugă numărul de bytes citiți la variabila „file_sent_size”, și se trimite pachetul.

Dacă datele trimise au dimensiunea egală cu dimensiunea totală a fișierului, se setează variabila „type” la valoarea „-1” și se trimite pachetul, informând clientul că fișierul a fost trimis în întregime. Se închide fișierul care este trimis și socketul care făcea conexiunea între clienți. Se șterge din lista fișierelor în curs de trimitere, fișierul tocmai trimis. Stergerea se face în complexitate O(1), reindexând elementele listei. Se adaugă ulimul fișier pe poziția celui curent și se scade numărul elementelor. La consolă va apărea mesajul „Fișierul a fost trimis cu succes!”.

Funcția „accept_file” primește trei parametrii. Primul parametru este lista de fișiere în curs de descărcare, al doilea parametru reprezintă numărul acestor fișiere și ultimul parametru este variabila „i” care reprezintă indexul fișierului care se descarcă.

Se creeză un pachet care se va completa cu datele primite. Se verifică tipul variabile „type”, și în cazul în care variabila are valoarea mai mare decât „-1”, se scriu datele în fișierul deschis pentru scriere. Datele se scriu folosind funcția „fwrite” care este similară cu funcția „fread”, și primește aceiași parametrii. Dacă variabila „type” este egală cu „-1” se închide fișierul care a fost scris, și socketul care făcea conexiunea cu celălalt client. Fișierul este șters din lista de fișiere în curs de descărcare tot în complexitate O(1). Pe ecran va apărea mesajul „Fișierul a fost descărcat cu succes!”.

quit

Clientul poate ieși oricând de pe server folosind comanda „quit”. Când un client iese de pe server toate fișierele partajate for vi șterse din listă și el va fi șters din lista de clienți. De asemenea vor fi șterse și fișierele care sunt în curs de descărcare de la ceilați clienți din lista acestora.

Funcția implementată pe client primește ca parametru socket file descriptorul conectat la server datele despre clientul care o apelează, fișierele care sunt în curs de trimitere, fișierele care sunt în curs de descărcare și numărul acestora. Se creează un pachet și se setează variabila „type” la valoarea „0”. Clientul va trimite pachetul către server anunțându-l pe acesta ca vrea sa iasă din sistem. După ce trimite pachetul,clientul inchide toți sockeții care fac legătura cu alți clienți și toate fișierele deschise de acesta, apoi închide și socketul care face conexiunea cu serverul. La final se închide și programul folosind funcția „exit”.

Serverul primește „pachetul” de la client și apelează funcția „quit_client” implementată pe server. Aici funcția primește următorii parametrii: primul parametru este socketul care este conectat la client, al doilea parametru este lista de clienți conectați, al treilea parametru este numărul clienților, al patrulea parametru reprezintă lista de fișiere partajateal cincilea parametru reprezintă numărul acestor fișiere, iar ultimul parametru este pachetul primit de la clientul care vrea să se deconecteze, conținând numele acestuia.

Serverul trimite celorlalți clienți un pachet care conține numele celui care se deconectează, iar variabila type a acestui pachet este setată la valoarea „9”. După ce clienții vor primii acest pachet, vor apela funcția „remove_data” care va șterge toate datele legate de clientul care se deconectază.

Funcția „remove_data” primește cinci parametrii. Primul parametru este lista de fișiere care sunt în curs de descărcare, al doilea parametru este numărul acestor fișiere, al treilea parametru este lista de fișiere în curs de trimitere, al patrulea parametru reprezintă numărul acestora, iar ultimul parametru este un pachet ce conține numele clientului care se deconectează. Funcția va parcurge fiecare listă, cea de fișiere care se trimit și cea de fișiere care se descarcă și se vor șterge fișierele de la persoana care vrea să se deconecteze. Ștergerea se face în complexitate O(1).

Pentru a nu folosi cod redundant, am creat o funcție numită „remove_file”, care primește doi parametri reprezentând două fișiere, și va copia datele celui de-al doilea fișier peste datele primului fișier. Funcția folosește ca parametrii, fișierul care se dorește a fi șters și ultimul fișier din listă.

După identificarea clientului în listă, care se face folosind comparația între socket file descriptorul pe care a venit mesajul și socket file descriptorul setat la conectarea clientului, se șterge clientul în complexitate O(1), reindexând lista de clienți, și se vor șterge și fișierele partajate ale acestuia tot în complexitate O(1). La finalul funcției se închide socketul care face conexiunea cu clientul.

Implementarea comenzilor server

Serverul, spre deosebire de client are doar două comenzi, ce pot fi trimise de la tastatură:

1.status

Comanda „status” afișează la consola serverului date despre toți clienții conectați, cum ar fi: numele, adresa IP, portul sau fișierele partajate. Funcția implementată în server primește patru parametrii: primul parametru reprezintă lista de clienți conectați, al doilea parametru reprezintă numărul acestor clienți, al treilea parametru este lista fișierelor partajate, și ultimul parametru reprezintă numărul fișierelor. Funcția verifică dacă numărul clienților este mai mare decât „0”, iar în acest caz va parcurge lista de clienți conectați la server, și pentru fiecare va afișa la consolă numele acestuia, adresa IP, portul și fișierele partajate.

Pentru a afișa la consolă și fișierele partajate, se parcurge lista fișierelor pentru fiecare client în parte, și se vor afișa doar fișierele care corespund fiecăruia. Corespondeța este dată de numele clientului. La consolă va apărea doar numele fișierului, nu întreaga cale. Acest lucru se face folosind funcția „basename”.

Dacă numărul clienților nu este mai mare decât „0”, la consolă se va afișa mesajul „Nu sunt clienți conectați!”.

2.log

Sistemul are implementat și un fișier de log, unde scrie toate comenzile executate de toți clienții. Acest fișier este completat în momentul utilizării comenzii. La pornirea serverului este creat un fișier numit „log.txt”. Fișierul este deschis în modul „a+”, adică pentru adăugare la sfârșit dar și pentru citire. Acest fișier este trimis ca parametru la toate funcțiile care reprezintă o comandă pentru client. Înaintea fiecărei intrări din fișier se scrie data curentă pentru a știi când a fost executată comanda respectivă.

Funcția „log” mută cursorul la începutul fișierului „log.txt” și afișează fișierul la consolă caracter cu caracter. Mutarea cursorului se realizează cu funcția „fseek”, iar citirea se realizează parcurgând tot fișierul caracter cu caracter până la întâlnirea caracterului „EOF”, care reprezintă sfârșitul fișierului.

3.quit

După executarea comenzii, în programul server se va apela funcția „quit”. Funcția primește doi parametrii, primul fiind lista de clienți conecați, iar al doilea reprezintă numărul clienților. După apelare, se crează un pachet care va fi trimis la fiecare client conectat. Variabila „type” a acestui pachet va fi setată la valoarea „0”. Programul server se va încheia folosind funcția „exit”.

După recepționarea pachetului de la server, clientul va verifica variabila „type” a acestui pachet. Dacă valoarea acesteia este egală cu „0”, la consola fiecărui client va fi afișat mesajul „Serverul a fost oprit!”, și se va executa funcția „exit” pentru închiderea programului client.

Probleme în implementare

La fel ca în orice aplicație, și aici au apărut probleme în implementare. Problemele au fost de cele mai multe ori cazuri speciale ale funcțiilor. De exemplu, folosirea comenzii „message” folosind ca parametru numele celui care o execută, sau folosirea comenzii „getfile” pentru un fișier care se află deja în lista de fișiere în curs de descărcare.

Vom exemplifica pentru funcțiile care au creat dificultăți la implementare, cazurile particulare:

Comanda „infoclient” poate fi apelată cu parametru sau fără parametru. Atunci când este apelată fără parametru, pe ecran va fi afișat mesajul „Nume invalid!”. Dacă funcția va fi apelată cu parametru, numele trebuie să existe în lista de clienți de pe server pentru a primi date despre acesta, altfel la consolă se va afișa mesajul „Clientul nu există!”.

Comanda „message” poate fi apelată cu un nume care nu există în lista de clienți de pe server, și în acest caz la consolă se va afișa mesajul „Clientul nu există!”, sau poate fi apelată cu numele celui care vrea să trimită mesajul, iar la consolă se va afișa mesajul „Nu îți poți trimite singur mesaje!”.

Comanda „sharefile” se poate apela cu numele unui fișier inexistent, și în acest caz la consolă se va afișa „Fișierul nu exista!”, sau se poate apela cu un fișier deja partajat, iar mesajul afișat la consolă în acest caz va fi „Fișierul este deja partajat!”.

Comanda „getshare” poate fi apelată fără niciun parametru, caz în care pe ecran se va afișa mesajul „Lipsește numele!”.

Comanda „getfile” poate avea ca parametru un fișier care nu este partajat, și la consolă se va afișa mesajul „Fișierul nu este partajat”, sau poate avea ca parametru un fișier care se descarcă deja, și în acest caz pe ecran va fi afișat „Fișierul este deja în lista de descărcare”.

Folosirea comenzii „quit” executată de client în timpul descărcării sau trimiterii unui fișier de către acesta, este o alta problemă întâlnită în implementare. Pentru tratarea ei, a fost necesar un nou algoritm și o nouă implementare a funcției.

Concluzii

Obiectivul principal al acestei lucrări este realizarea unui sistem de partajare a fișierelor în rețea. Alte obiective mai pot fi: înțelegerea mecanismelor de dezvoltare a aplicațiilor folosind sockeți, și dezvoltarea unei aplicații client-server ce folosește sockeți.

Descrierea aplicației

Aplicația client-server este dezvoltată folosind sockeți TCP pentru schimbul de mesaje și fișiere între clienți. În cadrul sistemului vor exista două entități: clienți și un server central care ajută la descoperirea clienților.

Serverul primește la pornire un parametru, care reprezintă socketul pe care acesta va asculta cereri de conexiune. Serverul se pornește folosind comanda:

./server 5001

Clientul primește trei parametrii la pornire: numele clientului după care va fi identificat în sistem, adresa IP și portul serverului pentru a se conecta la acesta. Un client se pornește cu următoarea comandă:

./client Radu 127.0.0.1 5001

Serverul este folosit pentru descoperirea clienților conectați, iar trimiterea de mesaje și fișiere se realizează direct între clienți. Serverul și clienții vor folosi apelul funcției „select” pentru multiplexarea comunicației.

Funcționalitate

După ce este pornit, serverul creează un socket și asteptă cereri de conexiune pe portul specificat ca parametru. La conectare, clientul trimite datele de identificare care se dau ca parametru la pornire (numele și portul pe care ascultă cererile de conexiune de la ceilalți clienți).

Serverul acceptă sau nu clientul în funcție de numele acestuia. Dacă numele exită deja în sistem, serverul nu acceptă clientul. Serverul reține penru fiecare client adresa IP și portul pe care acesta ascultă.

Funcțiile clientului

După ce se conectează la server, clientul poate primii una dintre cele opt comenzi:

listclients

Clientul trimite o cerere către server. Acesta va răspunde și îi va trimite clientului lista clienților conectați. La consolă se vor afișa clienții conectați, câte unul pe fiecare linie.

infoclient nume

Datele despre un client, cum ar fi portul pe care acesta ascultă și timpul care a trecut de la conectarea acestuia pe server, se pot afla folosind această funcție. Primește ca parametru numele clientului despre care se cer informații suplimentare.

message nume mesaj

Această funcție este folosită pentru a trimite mesaje altor clienți. Trimiterea mesajelor se realizează printr-o conexiune directă între clienți. Clientul care primește mesajul îl va afișa la consolă împreună cu numele celui care l-a trimis.

sharefile fișier

Cu această comandă un client poate să partajeze un fișier. Acesta trimie către server numele fișierului pe care vrea să îl partajeze. Serverul adaugă fișierul în lista fișierelor partajate și informează clientul că operația s-a executat cu succes.

unsharefile fișier

Comanda efectuează operația inversă comenzii anterioare. Se trimite către server fișierul care va fi șters din lista de fișiere partajate. Serverul îi confirmă clientului dacă funcția a fost executată cu succes.

getshare nume

Un client poate vedea toate fișierele partajate de un alt client folosind această comandă. Se trimite ca parametru numele clientului despre care se cer informații. Serverul răspunde cu lista fișierelor pe care acesta le are partajate.

getfile fișier

Se descarcă un fișier de la un alt client. Transferul se face direct între cei doi clienți. Trimiterea fișierului se face în segmente de 1024 bytes pentru a permite executarea altor comenzi. Clientul nu trebuie să rămână blocat în timpul transferului și de aceea este nevoie de acest mecanism.

quit

Clientul poate ieși oricând din sistem cu această comandă. Ieșirea din sistem se face după ce clientul închide toate conexiunile. Serverul anuntă ceilalți clienți că un utilizator a părăsit sistemul.

Funcțiile serverului

Serverul poate primii doar două comenzi de la tastatură:

status

La executarea acestei comenzi, la consola serverului vor fi afișate datele fiecărui client (nume, adresă IP, port), precum și fișierele pe care aceștia le au partajate.

log

Sistemul are un fișier de log unde sunt memorate toate comenzile executate de clienți. În dreptul comenzilor va fi scris și timpul care care aceasta s-a executat.

quit

Această comandă este folosită pentru oprirea serverului. Clienții sunt informați și serverul închide toate conexiunile.

Serverul și clienții pot executa comenzile în orice ordine. Serverul trebuie să asculte cereri noi de conexiune în orice moment, iar pentru asta trebuie să seteze intern un socket.

Similar Posts