Proiectarea Si Programarea In Java a Aplicatie Denumita Schimb de Carti

Introducere

Internetul există de peste 25 de ani și a trecut de mult peste stagiul de experiment. In acest moment este stabil și larg folosit. Probabil acesta a contribuit mai mult decât televiziunea prin satelit la realizarea satului global. Oricine a trimis un e-mail sau un mesaj peste ocean și a primit răspunsul în mai puțin de câteva minute a înțeles mai bine ideea de sat global decât uitându-se la o emisiune transmisă pe tot continentul. Rețeaua de calculatoare, obiectivul primar al ARPANETului, a devenit fără a ne da seama o rețea de oameni. De la un timp se vorbește de oamenii care aparțin unor comunități virtuale compuse nu din oamenii ce aparțin aceluiași spațiu geografic, ci de cei uniți de un newsgroup, un grup de pe o rețea de socializare.

Totodată acesta a devenit un „spațiu” foarte ușor de folosit/exploatat pentru cei ce doresc să își dezvolte afacerea sau de a începe una. Acesta abilitate de a lega calculatorul personal la o rețea a făcut calculatorul un instrument incredibil de puternic pentru mediul de afaceri.

Toate acestea sunt posibile cu ajutorul „Web-ului”. Aici putem introduce termenul de aplicație. O aplicație web este de fapt un program ce rulează în browser-ul web de pe care este accesată (aplicația) și este creată într-un limbaj de programare interpretabil de către browser. Aplicațiile sunt populare pentru capacitatea lor de a fi actualizate și menținute fără a distribui și instala software-ul pe potențialele mii de calculatoare.

Putem găsi aplicații web oriunde pe internet. Multe din acestea sunt folosite pentru a procesa formulare online, număra voturile dintr-o secție, a lua comenzile dintr-un magazin online, permite utilizatorilor să își rezerve un bilet de avion pentru viitoarea lor călătorie de afaceri, sau pur și simplu pentru a afișa numele de login al utilizatorului.

Capitolul 1

Arhitectura rețelelor de calculatoare

Ultimele trei secole au fost dominate fiecare de câte o tehnologie. Secolul al XVIII-lea a fost secolul marilor sisteme mecanice. Secolul XIX a fost acaparat de mașinile cu abur. În secolul XX tehnologia predominantă este legată de colectarea și distribuirea informației. Am asistat la instalarea rețelelor telefonice mondiale, la invenția radioului (FM, tendințele noi duc către digitalizarea acestuia) și a televiziunii, la apariția rețelelor de calculatoare și lansarea sateliților de comunicații. Deși industria de calculatoare este încă tânără aceasta a cunoscut o dezvoltare spectaculoasă în ultimele decenii. Întrepătrunderea dintre calculator și telecomunicații a avut o influență asupra modului în care sunt concepute centrele de calcul. Modelul vechi în care un singur calculator deservea o organizație, a fost înlocuit de un model în care un număr mare de calculatoare sunt interconectate, acest sistem numindu-se rețele de calculatoare.

Definiție: O rețea de calculatoare reprezintă un ansamblu de calculatoare (sisteme de calcul) interconectate prin intermediul unor medii de comunicație (cablu coaxial, fibră optică, linie telefonică) în scopul utilizării în comun de către un număr mare, chiar la nivel mondial a tuturor resurselor fizice (hardware), logice (software de bază și aplicații) și informaționale (baza de date) asociate calculatoarelor din rețea. Prin astfel de rețele de calculatoare asigura o integrare informatică a unui număr foarte mare de utilizatori la nivel local, regional și mondial.

Utilizările rețelelor de calculatore

În acest paragraf vom prezenta utilizările tradiționale în cadrul companiilor și utilizatorilor individuali.

1.1.1 Aplicații comerciale. Majoritatea companiilor au un număr semnificativ de calculatoare. La început aceste calculatoare puteau lucra izolat, dar la un moment dat conducerile au luat decizia de a le conecta între ele pentru a putea corela și extrage informații din acestea. În general acest subiect se referă la împărțirea resurselor, iar scopul este de a face ansamblul de programe, echipamente și în special datele disponibile la orice terminal din rețea, indiferent de localizarea fizică a resursei și a utilizatorului. Un exemplu uzual ar fi un grup de utilizatori care folosesc la comun o imprimantă. Nici unul dintre aceștia nu are nevoie de propria imprimantă, iar o imprimantă performantă legată în rețea este de multe ori o soluție mai ieftină, rapidă și ușor de întreținut decât o colecție de imprimante (una pentru fiecare utilizator). Mult mai importantă decât partajarea resurselor fizice (imprimante, scannerele) este partajarea informației. Orice companie mare sau medie chiar și cele foarte mici sunt dependente de informația prelucrată de calculatoare. Cele mai multe companii își țin înregistrările clienților, inventarele, informațiile despre taxă cât și alte informații cu ajutorul calculatorului. Dacă într-o bancă s-ar defecta toate calculatoarele aceasta nu ar mai putea funcționa nici 5 minute, iar o linie de producție dintr-o fabrică condusă de un calculator nici măcar atât. Pentru companiile mici toate calculatoarele pot fi centralizate într-o singură clădire sau birou, iar pentru companiile mari pot fi pe mai multe continente. Cu toate acestea un angajat din Berlin poate accesa o baza de date din Beijing, cu alte cuvinte distanța foarte mare de mii de kilometri nu îl împiedică să folosească datele ca și cum ar fi locale. Cel mai simplu e să ne imaginăm că toate informațiile unei companii sunt alcătuite din una sau mai multe baze de date stocate în calculatoare foarte performante numite servere. Acestea sunt centralizate și întreținute de un administrator de sistem. Angajații au sisteme de calcul mai simple numite clienți amplasate pe birourile acestora. Acestea doua (mașinile server cat și cele client sunt conectate la rețea).

1.1.2 Aplicații domestice. De ce cumpără oamenii calculatoare pentru a le folosi de la domiciliu? În urmă cu aproximativ un deceniu majoritatea persoanele ce achiziționau un calculator o făceau pentru jocuri și prelucrarea de texte, dar în acest moment lucrurile s-au schimbat radical. Cel mai probabil în acest moment cel mai important motiv este pentru accesul la internet, chiar dacă pe piață au apărut smartphone-urile care au prins foarte bine. Cele mai importante utilizări ale computerului de acasă ar putea fi:

1. Accesul la informație de la distanță.

2. Comunicațiile interpersonale.

3. Divertismentul interactiv.

4. Comerțul online.

Accesul la informație de la distanță ia forme multiple. Multe organizații profesionale au disponibile on-line multe dintre jurnale și prezentări. Toate aceste aplicații presupun interacțiuni între o persoană și o bază de date aflată la distanță.

O a doua categorie largă de utilizări ale rețelei este comunicarea între persoane. Poșta electronică este folosită în zilele noastre de milioane de persoane, iar numărul acestora este într-o continuă creștere. Orice adolescent a utilizat și utilizează în continuare mesageria instantanee. Această facilitate este derivată dintr-un program UNIX numit talk apărut în anul 1970 ce le permite celor 2 persoane aflate în fața unui computer să își trimită mesaje în timp real unul altuia.

Un tip de comunicații se numește comunicație de la egal la egal (peer-to-peer). În această formă persoanele care formează un grup comunică în cadrul acestuia după cum se vede în următoarea figură. Fiecare persoană poate să comunice cu una sau mai multe persoane din cadrul grupului fără a exista o departajare între clienți și servere.

Figură 1.1 Utilizările rețelei de calculatoare într-un sistem de la egal la egal nu sunt clienți sau server fixe.

1.2 Hardware-ul rețelei.

Acest paragraf se concentrează pe aplicațiile și problemele interconectării, la aspectele tehnice privind proiectarea rețelelor. În acest punct de vedere sunt extrem de importante două criterii: tehnologia de transmisie și scara la care operează. Tot odată există doua tipuri de transmisie care operează pe o scară largă.

1. Legături cu difuzoare.

2. Legături punct – la – punct.

1.2.1 Rețelele cu difuzore au un singur canal de comunicații care este partajat de toate computerele din rețea. Orice mașină poate transmite mesaje scurte numite adesea pachete, care sunt recepționate de toate celelalte mașini. Un câmp de adresă din pachet specifică computerul căruia ii este adresat. La recepționarea unui pachet o mașină se uita la câmpul de adresă, dacă ii este adresat aceasta îl prelucrează iar dacă nu pachetul este ignorat.

1.2.2 Rețelele punct – la – punct dispun de mai multe conexiuni între perechi de mașini individuale. Pentru a ajunge de la emițător la receptor un pachet pe o rețea de acest tip va trebui să treacă prin una sau mai multe mașini intermediare. Descoperirea drumurilor celor mai potrivite este foarte importantă. De regulă rețelele mai mici localizate geografic tind să utilizeze difuzarea în timp ce cele mai mari sunt punct – la – punct.

Figură 1.2 Clasificarea procesoarelor interconectate în funcție de dimensiune.

Un alt criteriu pentru clasificarea rețelelor este dimensiunea acestora. În fig. anterioară 1.2 este reprezentată o clasificare a sistemelor cu procesoare multiple după dimensiunea lor. O rețea fără fir care conectează calculatorul cu componentele periferice (tastatură, mouse, scanner) se numește rețea personală. Mai sus decât aceste rețele sunt rețelele cu domenii mai mari. Acestea pot fi împărțite în rețele locale, rețele metropolitane, și rețele larg răspândite geografic. Mai jos prezentăm aceste trei tipuri de rețele:

1.2.3 Rețelele Locale (Local Area Networks) sunt rețele private localizate într-o singură clădire sau într-un campus de cel mult câțiva kilometri. Acestea sunt cel mai frecvent folosite pentru a conecta stațiile de lucru aflate în birourile marilor companii în scopul de a partaja resurse și de a schimba informații. LAN-urile se deosebesc prin trei criterii de celelalte tipuri de rețele: mărime, tehnologie de transmisie și topologie.

Ca și mărime acestea au dimensiuni restrânse ceea ce înseamnă că timpul de transmisie în cazul cel mai defavorabil este limitat și cunoscut dinainte. Administrarea acestora este mai simplă decât în celelalte cazuri. LAN-urile utilizează o tehnologie de transmisie care constă dintr-un singur cablu la care sunt atașate toate mașinile. Acestea lucrează la viteze cuprinse între 10-100 Mbps și au întârzieri mici de nivelul microsecundelor sau nanosecundelor.

1.2.4 Rețele Metropolitane O rețea metropolitană ( Metropolitan Area Network) sau MAN deservește un oraș. Un exemplu foarte bun ar putea fi o rețea de televiziune disponibilă prin cablu cum există în majoritatea orașelor. Televiziunea prin cablu nu este singurul MAN. Ultimele dezvoltări în domeniul accesului la internet fără fir a dus la dezvoltarea unei noi rețele metropolitane care a fost standardizată cu numele de IEEE 802.16.

1.2.5 Rețele larg răspândite geografic (Wide Area Network), sau WAN, se află pe arie întinsă geografic. Acestea se referă de multe ori la o țară sau chiar un continent. Rețeaua conține o serie de mașini folosite pentru a executa programele utilizatorilor (aplicații).

Aceste mașini se mai numesc și gazde. Gazdele sunt conectate între ele printr-o subrețea. Gazdele aparțin clienților dar subrețeaua de comunicație este de cele mai multe ori exploatată de o companie de telefonie sau un furnizor de servicii internet (ISP). Majoritatea rețelelor de acest tip, au subrețelele formate din două componente distincte. Linii de transmisie care transportă biții între mașini și elementele de comutare fiind calculatoare speciale care sunt folosite pentru a conecta două sau mai multe linii de transmisie.

1.3 Modele de referință

În rețelele de calculatoare din ziua de astăzi, comunicațiile între utilizatori este realizată printr-o succesiune de activități organizate într-o maniera ierarhizată. În cadrul fiecărui dispozitiv ce face parte din sistemul rețelei de calculatoare se delimitează un număr de n diviziuni ierarhice numite niveluri. Fiecare este realizat pe baza celui inferior și interacționează doar cu nivelurile adiacente. Rolul fiecăruia este de a oferi nivelului superior anumite funcții numite servicii ce tind la buna funcționare a rețelei și pe care se bazează următorul nivel pentru a realiza serviciile pe care le oferă la rândul lei. Această ierarhizare oferă avantajul modulării

Elementul activ ce generează o funcție în cadrul unui nivel se numește entitate sau modul. Acesta poate fi de tip software (un anumit program) sau de tip hardware (de exemplu un chip inteligent de intrare-ieșire). Conform organizării pe niveluri ierarhice a comunicației de rețea, nivelul (de rang) n al unui dispozitiv comunică doar cu nivelul de același rang n al oricărui alt dispozitiv.

Algoritmul distribuit (la mai multe sau la toate dispozitivele între care se face comunicația în rețea) și care traduce regulile și convențiile stabilite (cunoscute și utilizate de toate dispozitivele participante) pentru realizarea unei comunicații (sesiuni) între entitățile pereche de la nivelul n formează un protocol de nivel n.

Convențiile într-un protocol sunt:

semantice (de semnificație), care privesc semnificația semnalelor vehiculate: semnale informaționale (date), semnale de stare (de supraveghere) și semnale de control;

de sintaxă (de asamblare a semnalelor), ce specifică dimensiunile, amplasamentul și rolul elementelor constitutive ale semnalelor.

Regulile unui protocol (formând succesiunea de desfășurare a protocolului) rezultă din combinarea convențiilor susmenționate și reprezintă secvența de semnale elementare, numite unități de date de protocol ( Protocol Data Unit [PDU]), schimbate între ele de entitățile pereche pentru realizarea unei comunicații.

Mulțimea nivelurilor ierarhice și a protocoalelor aferente formează arhitectura rețelei.

Cu excepția primului nivel (cel inferior), la care se realizează efectiv o conexiune fizică între entitățile pereche, la toate celelalte niveluri comunicația între entitățile pereche este virtuală, căci informațiile nu sunt transferate direct între nivelurile de rang n ale dispozitivelor comunicante ci, în cadrul fiecărui dispozitiv emițător mesajele informaționale (împreună cu niște informații de control) sunt trecute succesiv nivelurilor imediat inferioare, până la nivelul 1 (unde se face transmisia efectivă a semnalelor între dispozitivele comunicante) și apoi la dispozitivul receptor, trecute de la fiecare nivel la succesorul lui, până ajung la nivelul n.

Figura 1.3 Niveluri, protocoale și interfețe

Prin interfețe se înțelege un set de reguli și convenții utilizate între entități nesimilare din același dispozitiv. Aceste unități interacționează printr-o conexiune fizică. Între oricare două niveluri adiacente dintr-un dispozitiv comunicant al rețelei există o interfață care definește ce servicii oferă nivelul inferior celui superior.

Proiectarea interfețelor trebuie să răspundă la două cerințe:

minimizarea cantității de informație care se vehiculează între niveluri;

insensibilizarea serviciilor pe care le oferă un nivel față de modul de implementare al acestuia.

Problematica proiectării (protocoalelor) nivelurilor ierarhice ale unei rețele de calculatoare trebuie să aibă în vedere următoarele:

prevederea unei modalități de stabilire a conexiunilor la fiecare nivel, în particular a unui mod de specificare a adreselor interlocutorilor;

prevederea unei modalități de întrerupere a conexiunilor la terminarea comunicației;

stabilirea regulilor privind transferul informațiilor și anume:

comunicație simplex, comunicație semi-duplex sau comunicație duplex

numărul de canale logice care corespund unei conexiuni și prioritățile lor

asigurarea protecției la erori (error control), adică prevenirea, depistarea și eventual corectarea erorilor introduse de perturbațiile care afectează canalul fizic, prin:

utilizarea unor coduri detectoare și chiar corectoare de erori;

prevederea unor posibilități ca receptorul de mesaje să poată confirma dispozitivului emițător dacă mesajele ce i-au fost adresate au fost corect recepționate sau nu;

posibilitatea refacerii ordinii fragmentelor de mesaj la recepție, atunci când modul de transmisie nu păstrează succesiunea de la emisia lor.

evitarea – la fiecare nivel ierarhic – a „înecării” cu mesaje a unui receptor lent de către un emițător rapid, utilizând o reacție care să informeze dispozitivul emițător despre starea curentă a receptorului, stopându-i, la nevoie, temporar emisia;

tratarea lungimilor inacceptabile de mesaje în cazurile:

● unor mesaje prea lungi în raport cu durata proceselor ce comunică între ele prin dezasamblarea mesajelor în fragmente, transmiterea lor (succesivă sau simultană, pe aceeași cale sau pe trasee diferite – după cum permit canalele și metoda de comutație folosită) și reasamblarea lor la recepție;

● unor mesaje neeconomic de scurte și având același destinatar – prin concatenarea lor la emisie și descompunerea la recepție a mesajului rezultat în componentele sale;

– posibilitatea utilizării unei aceleiași conexiuni de la un anumit nivel pentru transmisia mai multor mesaje necorelate de la nivelurile superioare – prin operații de multiplexare – demultiplexare

– alegerea traseului dintre sursă și destinație, atunci când există – la oricare nivel – mai multe posibilități.

1.3.1 Modelul de referință OSI

Modelul are la bază o propunere prezentată și dezvoltată de către Organizația Internațională de Standardizare ( Internațional Standards Organization ISO) fiind un prim pas în standardizarea internațională a protocoalelor folosite pe niveluri diferite(Day și Zimmermann, 1993). Revizuit fiind în 1995 (Day, 1995). Aces model se numește ISO OSI (Open Systems Interconnection, Interconectarea sistemelor deschise), deoarece el se ocupa de sistemelor deschise, cu alte cuvinte a sistemelor deschise comunicării cu alte sisteme. În cele ce urmează vom folosi in special termenul de model OSI.

Modelul OSI cuprinde șapte niveluri. Principiile aplicate pentru a se ajunge la cele șapte niveluri sunt următoarele:

1. Un nivel este creat în cazul în care este nevoie de un nivel de abstractizare diferit 2. Rolul fiecărui nivel este bine definit.

3. Funcția nivelului este aleasă cu mare grijă deoarece trebui acordata o atenție sporită definirii de protocoale standardizate pe plan internațional.

4. Delimitarea între nivele este făcută astfel încât fluxul de informații să fie cât mai minimizat.

5. Numărul de niveluri trebuie să fie mare astfel încât în același nivel să nu existe funcții diferite dar și suficient de mic pentru ca funcționalitatea arhitecturii să nu fie afectată.

In rândurile ce urmează vom discuta fiecare nivel în parte al modelului, Vom începe cu cele aflate la bază. Modelul OSI nu prezintă în mod explicit o arhitectură de rețea deoarece nu specifică protocoalele și serviciile utilizate la fiecare nivel. OSI ne transmite doar ce ar trebui să facă fiecare nivel. ISO a produs standarde pentru fiecare nivel însă acestea nu fac parte din modelul de referință acestea fiind publicate ca standarde separate.

Figura 1.4 Modelul de referință OSI

Nivelul Fizic. Acesta se ocupă cu transmiterea biților printr-un canal de comunicație. Proiectarea trebuie să garanteze că atunci când unul din capete transmite un bit 1, acesta va fi recepționat de celălalt capăt tot ca un bit 1 și nu 0. Problemele se referă la câți volți vor trebui utilizați pentru a reprezenta un 1 și câți pentru un 0, dacă transmisia poate avea loc simultan în ambele sensuri. Cum este stabilită conexiunea și cum este întreruptă când ambele parți au terminat de comunicat, câți pini are conectorul de rețea și la ce folosesc. Aceste aspecte de proiectare au o legătură strânsă cu interfețele mecanice, electrice, funcționale și procedurale, ca și mediul de transmisie situat sub nivelul fizic.

Nivelul legătură de date. Are drept sarcină principală transformarea unui mijloc oarecare de transmisie într-o linie disponibilă nivelului rețea fără erori de transmisie nedetectate. Acesta realizează sarcina obligând emițătorul să descompună datele de intrare în cadre de date ( câteva sute sau câteva mii de octeți) și să transmită cadrele secvențial. Dacă serviciul este sigur, receptorul trimite înapoi câte un cadru de confirmare pozitiv pentru fiecare cadru. O altă problemă care apare la nivelul legătură de date (și la majoritatea nivelurilor superioare este evitarea inundării unui receptor lent cu datele provenite de la un emițător rapid. În acest scop sunt necesare mecanisme de reglare a traficului care să permită emițătorului să afle cât spațiu tampon deține receptorul la momentul curent. . Rețelele cu difuzare determină în nivelul legătură de date o problemă suplimentară: cum să fie controlat accesul la canalul partajat. De această problemă se ocupă un subnivel special al nivelului legătură de date și anume subnivelul de control al accesului la mediu.

Nivelul rețea. Se ocupă de controlul funcționării subrețelei. O problemă ridicată este determinarea modului în care pachetele sunt dirijate de la sursă la destinație. Dirijarea se bazează sau se poate baza pe tabele statistice care se află inter în rețea. Traseele se pot stabili la începutul fiecărei conversații. Dirijarea poate fi dinamică, traseele determinându-se pentru fiecare pachet în concordanță cu traficul din rețea. În subrețea se pot produce gâtuiri în momentul în care există prea multe pachete simultan, care intră unul pe traseul celuilalt. Controlul acestor gâtuiri ii revine acestui nivel, mai precis calitatea serviciilor este o responsabilitate nivelului rețea (întârziere, timp de tranzitare).

O altă problemă majoră poate să apară atunci când un pachet trebuie să tranziteze mai multe rețele pentru a ajunge la destinație. Modul de adresarea al unei rețele poate să difere de modul de adresare al alteia. Presupunem că avem două rețele, a doua rețea ar putea chiar să nu accepte deloc pachetul pentru că este prea mare sau protocoalele pot s fie diferite și așa mai departe. Rezolvarea problemelor de acest tip în vederea interconectării rețelelor este de asemenea o sarcină ce revine nivelului rețea. În rețelele cu difuzoare, problema dirijării este simplă, astfel că nivelul rețea este deseori foarte mic sau uneori nu există.

Nivelul Transport. Rolul acestui nivel este de a accepta date de la nivelul superior adică sesiune și de a le descompune, în funcție de caz în unități mai mici, apoi să le transfere nivelului rețea și să se asigure că toate fragmentele sosesc corect la celălalt capăt. Toate aceste operații trebuie făcute eficient și într-un mod care izolează nivelurile de mai sus de modificările inevitabile în tehnologia echipamentelor. Nivelul transport determină ce tip de serviciu va furniza nivelului sesiune și utilizatorilor rețelei. Cel mai frecvent tip de conexiune este un canal punct – la – punct care furnizează fără erori mesajele sau octeții în ordinea trimiterii acestora. Alte tipuri de transport sunt transportul mesajelor individuale care nu au nici o garanție în privința ordinii de livrare și difuzarea mesajelor către destinații multiple. Tipul serviciului este determinat la stabilirea conexiunii.

Nivelul transport poate fi un nivel capăt – la – capăt ( sursă – destinație). Un program de pe o mașină sursă comunică cu un program similar de o mașină destinație, folosind în acest scop antetele mesajelor și mesaje de control. În nivelurile inferioare protocoalele au loc între fiecare mașină și vecinii săi imediați (niveluri înlănțuite), și nu direct între mașinile sursă și destinație (niveluri capăt – la – capăt ), care pot fi separate de numeroase rutere. Diferența între nivelurile de la 1 până la 3, care sunt înlănțuite și nivelurile de la 4 la 7, care sunt capăt – la – capăt, este ilustrată în figura 1.5.

Figura 1.5 Modelul de referință OSI

Nivelul Sesiune. Nivelul sesiune permite utilizatorilor de pe mașini diferite să stabilească între ei sesiuni. Sesiunile oferă diverse servicii, incluzând controlul dialogului, gestionarea jetonului( prevenirea situației în care 2 entități încearcă aceeași operație critică în același timp) și sincronizarea ( introducerea de puncte de control pe parcursul transmisiilor lungi, astfel în cazul unui eșec să se poată retransmite de un rămăseseră).

Nivelul prezentare. Spre deosebire de nivelurile inferioare, care se ocupă numai de transportul biților, nivelul prezentare se ocupă de sintaxa și semantica informațiilor transmise. Pentru a face posibilă comunicarea între calculatoare cu reprezentări diferite ale datelor, structurile de date care se schimba între ele pot fi definite într-un mod abstract, alături de o codificare standardizată ce va fi utilizată „pe cablu”. Nivelul prezentare gestionează aceste structuri de date abstracte și permite definirea și comunicarea unor structuri de date de nivel mai înalt (de ex. înregistrări bancare).

Nivelul Aplicație. Conține o mare varietate de protocoale frecvent utilizate. Un exemplu utilizat la scară largă este HTTP (HyperText Transfer Protocol) care sta la baza WWW ( World Wide Web). Atunci când un program de navigare numit browser accesează o pagină web, trimite serverului numele pagini care este solicitată folosind protocolul HTTP, iar serverul trimite ca răspuns pagina. Alte protocoale sunt folosite pentru transferul fișierelor, poștă electronică, știri în rețea.

1.3.2 Modelul de referință TCP/IP

ARPANET, strămoșul Internet-ului, a fost o rețea de cercetare sponsorizată de către DoD (U.S. Department of Defense – Departamentul de Apărare al Statelor Unite). În cele din urmă, rețeaua a ajuns să conecteze între ele, utilizând linii telefonice închiriate, sute de rețele universitare și guvernamentale. Atunci când au fost adăugate, mai târziu, rețele prin satelit și radio, interconectarea acestora cu protocoalele existente a pus diferite probleme. Era nevoie de o nouă arhitectură de referință. De aceea, posibilitatea de a interconecta fără probleme mai multe tipuri de rețele a reprezentat de la bun început un obiectiv de proiectare major. Această arhitectură a devenit cunoscută mai târziu sub denumirea de modelul de referință TCP/IP, dată după numele celor două protocoale fundamentale utilizate. Arhitectura respectivă a fost definită prima dată în 1974 (Cerf și Kahn), o perspectivă ulterioară fiind prezentată în 1985 (Leiner). Filozofia de proiectare din spatele modelului este discutată în 1988 (Clark).

Dată fiind îngrijorarea Departamentului de Apărare că o parte din prețioasele sale gazde, rutere și porți de interconectare ar putea fi distruse dintr-un moment în altul, un alt obiectiv major a fost ca rețeaua să poată supraviețui pierderii echipamentelor din subrețea fără a fi întrerupte conversațiile existente. Cu alte cuvinte, DoD dorea ca atâta timp cât funcționau mașina sursă și mașina destinație, conexiunile să rămână intacte, chiar dacă o parte din mașini sau din liniile de transmisie erau brusc scoase din funcțiune. Mai mult, era nevoie de o arhitectură flexibilă, deoarece se aveau în vedere aplicații cu cerințe divergente, mergând de la transferul de fișiere până la transmiterea vorbirii în timp real.

Toate aceste cerințe au condus la alegerea unei rețele cu comutare de pachete bazată pe un nivel inter-rețea fără conexiuni. Acest nivel, numit nivelul internet, este axul pe care se centrează întreaga arhitectură. Rolul său este de a permite gazdelor să emită pachete în orice rețea și a face ca pachetele să circule independent până la destinație (fiind posibil ca aceasta să se găsească pe o altă rețea). Pachetele pot chiar să sosească într-o ordine diferită față de cea în care au fost trimise, caz în care – dacă se dorește furnizarea lor ordonată rearanjarea cade în sarcina nivelurilor de mai sus. De observat că "internet" este folosit aici într-un sens generic, chiar dacă acest nivel este prezent și în Internet.

Nivelul internet definește oficial un format de pachet și un protocol numit IP (Internet Protocol – protocol Internet). Sarcina nivelului internet este să furnizeze pachete IP către destinație. Problemele majore se referă la dirijarea pachetelor și evitarea congestiei. În consecință, este rezonabil să spunem că nivelul internet din TCP/IP funcționează asemănător cu nivelul rețea din OSI. Figura 1.3 arată această corespondență.

OSI TCP/IP

Figura 1.6 Modelul de referință TCP/IP

Nivelul Transport. Nivelul situat deasupra nivelului internet din modelul TCP/IP este frecvent numit nivelul transport. Acesta este proiectat astfel, încât să permită conversații între entitățile pereche din gazdele sursă și, respectiv, destinație, la fel ca în nivelul transport OSI. În acest sens au fost definite două protocoale capăt-la-capăt. Primul din ele, TCP (Transmission Control Protocol, rom: protocolul de control al transmisiei), este un protocol sigur orientat pe conexiuni care permite ca un flux de octeți trimiși de pe o mașină să ajungă fără erori pe orice altă mașină din inter-rețea. Acest protocol fragmentează fluxul de octeți în mesaje discrete și pasează fiecare mesaj nivelului internet. La destinație, procesul TCP receptor reasamblează mesajele primite într-un flux de ieșire. TCP tratează totodată controlul fluxului pentru a se asigura că un emițător rapid nu inundă un receptor lent cu mai multe mesaje decât poate acesta să prelucreze.

Al doilea protocol din acest nivel, UDP (User Datagram Protocol, rom: protocolul datagramelor utilizator), este un protocol nesigur, fără conexiuni, destinat aplicațiilor care doresc să utilizeze propria lor secvențiere și control al fluxului, și nu pe cele asigurate de TCP. Protocolul UDP este de asemenea mult folosit pentru interogări rapide întrebare-răspuns, client-server și pentru aplicații în care comunicarea promptă este mai importantă decât comunicarea cu acuratețe, așa cum sunt aplicațiile de transmisie a vorbirii și a imaginilor video. Relația dintre IP, TCP și UDP este prezentată în fig. 1.7. De când a fost dezvoltat acest model, IP a fost implementat pe multe alte rețele.

Figura 1.7 Protocoale și rețele din modelul TCP/IP inițial.

Nivelul aplicație. Deasupra nivelului transport se află nivelul aplicație. Acesta conține toate protocoalele de nivel mai înalt. Așa cum se vede din fig. 1.7, primele protocoale de acest gen includeau terminalul virtual (TELNET), transferul de fișiere (FTP) și poșta electronică (SMTP). Protocolul de terminal virtual permite unui utilizator de pe o mașină să se conecteze și să lucreze pe o mașină aflată la distanță. Protocolul de transfer de fișiere pune la dispoziție o modalitate de a muta eficient date de pe o mașină pe alta. Poșta electronică a fost la origine doar un tip de transfer de fișiere, dar ulterior a fost dezvoltat un protocol specializat (SMTP – Simple Mail Transfer Protocol, rom: Protocol simplu de transfer al poștei) pentru acest serviciu. Pe parcursul anilor, la aceste protocoale s-au adăugat multe altele, așa cum sunt Serviciul Numelor de Domenii (Domain Name Service – DNS) pentru stabilirea corespondenței dintre numele gazdelor și adresele rețelelor, NNTP, protocolul utilizat pentru a transfera articole de știri USENET, HTTP, folosit pentru aducerea paginilor de pe Web și multe altele.

Nivelul gazdă-rețea. Sub nivelul internet se află necunoscutul. Modelul de referință TCP/IP nu spune mare lucru despre ce se întâmplă acolo, însă menționează că gazda trebuie să se lege la rețea, pentru a putea trimite pachete IP, folosind un anumit protocol. Acest protocol nu este definit și variază de la gazdă la gazdă și de la rețea la rețea. Cărțile și articolele despre TCP/IP rareori discută despre acest protocol.

1.3.3 O comparație între modelele de referință OSI și TCP

Modelele de referință OSI și TCP/IP au multe lucruri în comun. Amândouă se bazează pe conceptul unei stive de protocoale independente. De asemenea, funcționalitatea nivelurilor este în linii mari similară. De exemplu, în ambele modele, nivelurile până la nivelul transport inclusiv sunt necesare pentru a pune la dispoziția proceselor care doresc să comunice un serviciu de transport capăt – la – capăt independent de rețea. Nivelurile respective formează furnizorul de transport. Din nou, în ambele modele, nivelurile de deasupra transportului sunt beneficiari orientați pe aplicații ai serviciului de transport. În pofida acestor similitudini fundamentale, între cele două modele există și multe deosebiri. În această secțiune ne vom concentra asupra diferențelor cheie dintre cele două modele de referință. Este important de subliniat că vom compara aici modelele de referință, nu stivele de protocoale corespunzătoare. Protocoalele propriu-zise vor fi discutate mai târziu. Pentru o întreagă carte consacrată comparației și diferențelor dintre TCP/IP și OSI, a se vedea (Piscitello și Chapin, 1993).

Trei concepte sunt esențiale pentru modelul OSI:

1. Servicii

2. Interfețe

3. Protocoale

Probabil că cea mai mare contribuție a modelului OSI este că a făcut explicită diferența între aceste trei concepte. Fiecare nivel realizează niște servicii pentru nivelul situat deasupra sa. Definiția serviciului spune ce face nivelul, nu cum îl folosesc entitățile de deasupra sa sau cum funcționează nivelul. El definește semantica nivelului. Interfața unui nivel spune proceselor aflate deasupra sa cum să facă accesul. Interfața precizează ce reprezintă parametrii și ce rezultat se obține. Nici interfața nu spune nimic despre funcționarea internă a nivelului. În sfârșit, protocoalele pereche folosite într-un nivel reprezintă treaba personală a nivelului. Nivelul poate folosi orice protocol dorește, cu condiția ca acesta să funcționeze (adică să îndeplinească serviciul oferit). Nivelul poate de asemenea să schimbe protocoalele după cum vrea, fără ca acest lucru să afecteze programele din nivelurile superioare. Aceste idei se potrivesc foarte bine cu ideile moderne referitoare la programarea orientată pe obiect. Un obiect, ca și un nivel, posedă un set de metode (operații) care pot fi invocate de către procese din afara obiectului. Semanticele acestor metode definesc mulțimea de servicii pe care le oferă obiectul. Parametrii și rezultatele metodelor formează interfața obiectului. Codul intern al obiectului reprezintă protocolul său și nu este vizibil și nici important în afara obiectului.

Deși lumea a încercat ulterior sa îl readapteze pentru a fi mai asemănător modelului OSI, modelul TCP/IP nu a făcut inițial distincție clară între serviciul, interfață și protocol. De exemplu, singurele servicii veritabile oferite de nivelul internet sunt SEND IP PACKET și RECEIVE IP PACKET.

În consecință, protocoalele din modelul OSI sunt mai bine ascunse decât în modelul TCP/IP și pot fi înlocuite relativ ușor pe măsură ce se schimbă tehnologia. Capacitatea de a face asemenea modificări reprezintă unul din scopurile principale ale organizării protocoalelor pe niveluri în modelul OSI.

Modelul de referință OSI a fost conceput înainte să fie inventate protocoalele. Ordinea respectivă semnifică faptul că modelul nu a fost orientat către un set specific de protocoale, fiind prin urmare destul de general. Reversul este că proiectanții nu au avut multă experiență în ceea ce privește acest subiect și nu au avut o idee coerentă despre împărțirea funcțiilor pe niveluri.

De exemplu, nivelul legătură de date se ocupa inițial cu rețelele punct-la-punct. Atunci când au apărut rețelele cu difuzare, a trebuit să fie introdus în model un subnivel nou. Când lumea a început să construiască rețele reale utilizând modelul OSI și protocoalele existente, s-a descoperit că acestea nu se potriveau cu specificațiile serviciului cerut, astfel că a trebuit introdusă în model convergența subnivelurilor, ca să existe un loc pentru a glosa pe marginea diferențelor. În sfârșit, comitetul se aștepta inițial ca fiecare țară să aibă câte o rețea care să fie în custodia guvernului și să folosească protocoalele OSI, așa că nu s-a dat nici o atenție interconectării.

În ceea ce privește TCP/IP, lucrurile stau exact pe dos: mai întâi au apărut protocoalele, iar modelul a fost de fapt doar o descriere a protocoalelor existente. Cu protocoalele respective nu era nici o problemă : ele se potriveau perfect cu modelul. Singurul necaz era că modelul nu se potrivea cu nici o altă stivă de protocoale. Prin urmare, modelul nu a fost prea util pentru a descrie alte rețele non-TCP/IP.

O diferență evidentă între cele două modele se referă la numărul de niveluri: modelul OSI are șapte niveluri, iar TCP/IP are patru. Ambele modele au niveluri (inter)- rețea, transport și aplicație, iar restul nivelurilor sunt diferite.

Capitolul II

Programarea orientată pe obiecte (POO)

Programarea cu obiecte (sau POO -programarea orientată pe obiecte) s-a impus atenției prin limbajul C++ (în 1987 apare cartea lui Bjarne Stroustroup) deși limbajul pur obiectual Smalltalk fusese inventat și folosit încă înainte de 1980, iar limbajul cu clase Simula (din care s-a inspirat si Stroustroup) este chiar și mai vechi (în jurul lui 1970).

2.1 Ce este specific programării orientate obiect?

În programarea procedurală, accentul cade pe fluxul operațiilor de prelucrare a datelor, pe succesiunea lor în timp. Proiectarea unui program C (Pascal, Fortran) înseamnă în principal stabilirea funcțiilor (subprogramelor) din componenta programului și a relațiilor dintre aceste funcții (cine pe cine apelează și în ce ordine). Datele prelucrate se transmit acestor funcții ca argumente (parametri) sau (mai rar) se definesc ca variabile externe, globale. Progresele realizate de la programarea cu instrucțiuni de salt (Fortran 66) la programarea structurată (Pascal, C, Fortran 90) au fost mai ales în sensul exprimării mai clare și mai sigure a succesiunii operațiilor de prelucrare (blocuri de instrucțiuni, decizii si cicluri).

În programarea cu obiecte accentul se mută pe obiectele de date care intervin într-o aplicație, iar prelucrările sunt în general asociate cu diferite obiecte (sub formă de "metode" de tratare a obiectelor). Obiectele pot fi mai simple (de exemplu, numere sau șiruri de caractere) sau mai complexe (o structură de date, un document, etc. ). Obiectele pot corespunde unor noțiuni din universul aplicației sau unor concepte abstracte. Proiectarea unui program Java înseamnă stabilirea claselor (obiectelor) ce contribuie la realizarea aplicației, a relațiilor dintre ele și a modului în care aceste obiecte interacționează (comunică între ele prin mesaje).

Așa cum nu există o soluție unică pentru definirea subprogramelor dintr-un program procedural, tot așa nu există o singură soluție pentru definirea și alegerea claselor dintr-un program orientat pe obiecte.

Ca orice nouă tehnologie, programarea cu clase prezintă avantaje și dezavantaje față de abordările anterioare, iar raportul dintre plusuri și minusuri depinde mult de specificul problemelor rezolvate.

Astfel, inginerii, matematicienii sau fizicienii care programează aplicații numerice vor fi greu de convins să renunțe la un limbaj simplu cum este limbajul Fortran pentru limbaje mai complexe ca Java sau C++, deoarece problemele numerice nu beneficiază semnificativ de abordarea cu obiecte, care poate părea doar o complicație inutilă, care conduce la programe mai lungi și mai puțin "naturale" (mai depărtate de formularea matematică a problemei).

Pe de altă parte, programatorii care realizează aplicații Windows sau alte aplicații în care interfața grafică a programului cu operatorul uman are o pondere importantă, apreciază simplificarea adusă prin utilizarea unor biblioteci de clase care încapsulează structuri de date si funcții Windows.

Pentru un număr mare de aplicații, de dimensiuni relativ mici, nici una din cele două abordări (procedurală sau obiectuală) nu este în mod evident superioară, dacă aplicația respectivă este privită separat de altele și nu se consideră aspectul reutilizării claselor în mai multe aplicații.

Trebuie avut în vedere și faptul că însușirea unui nou mod de abordare a programării necesită un efort inițial de adaptare, studiul unor aplicații existente și acumularea unei experiențe în definirea și utilizarea de obiecte.

2.2 Avantaje ale programării orientate obiect.

Programarea orientată pe obiecte este o tehnică de programare capabilă să reducă efortul de realizare a unor aplicații complexe, cu interfață grafică, cu baze de date și cu structuri de date nebanale.

Principala cale de stăpânire a complexității programelor este modularizarea lor, combinată cu reutilizarea unor module în mai multe programe. Modulele program pot fi scrise și verificate separat înainte de a fi asamblate într-o aplicație unică.

Mult timp, noțiunea de modul (funcțional) a însemnat un subprogram (funcție, procedură, subrutină). În multe limbaje, inclusiv în C, mai există și module de compilare (unități de traducere), care sunt de fapt fișiere sursă ce pot conține una sau mai multe funcții.

Aplicațiile mari pot conține zeci și sute de funcții, iar numărul funcțiilor apelate este mult mai mare: funcții standard ale limbajului, funcții din biblioteci, funcții pentru interfața grafică, ș.a. S-a mai observat că o parte din aceste funcții realizează operații asociate unor structuri de date folosite de aplicații sau operații legate de dialogul cu utilizatorii și sunt relativ independente de logica aplicației. Această observație sugerează că este posibil și un alt nivel de modularizare al programelor, cu module mai complexe decât funcțiile.

O clasă poate fi privită ca un modul de program mai cuprinzător deoarece grupează mai multe funcții în jurul unor date (sau chiar fără date comune). Avantajul utilizării unor module de program mai mari este însoțit, în cadrul POO, de posibilitatea reutilizării acestor module în diverse aplicații.

Un alt avantaj care rezultă din gruparea funcțiilor și datelor este reducerea numărului de argumente al funcțiilor (și, mai ales, al argumentelor modificabile, de tip pointer sau referință), deoarece metodele unei clase se pot referi la datele clasei ca și cum ar fi variabile globale (ele nu mai trebuie transmise ca argumente). De exemplu, metodele "push" și "pop", care pun sau scot ceva dintr-o stivă nu trebuie să mai aibă ca argumente variabila ce reprezintă stiva (un vector, de exemplu) și nici indicele vârfului stivei ("stack pointer").

Principala provocare a POO este chiar definirea de clase reutilizabile în cât mai multe aplicații. Deja există biblioteci de clase (de componente) reutilizabile pentru anumite domenii, cum sunt cel al realizării de interfețe grafice cu utilizatorii (GUI-Graphical User Interface), al structurilor de date, al accesului la bazele de date, ș.a.

POO a adus și alte metode de adaptare a modulelor reutilizate la specificul aplicațiilor: crearea de clase derivate sau doar modificarea proprietăților unor componente. O componentă (software) este o clasă utilizabilă ca atare (fără crearea de subclase) și care poate fi cuplată cu alte componente într-o aplicație fără programare sau cu un minim de programare, folosind un mediu vizual (un editor vizual de componente).

Derivarea de subclase dintr-o clasă de bază (superclasă) este o metodă mai sigură de a face ajustări importante în funcționalitatea unui modul, față de modificarea unor subprograme existente, deoarece nu se fac modificări în clasele preluate iar metodele moștenite nu mai trebuie testate.

Un alt avantaj al POO poate fi considerat și posibilitatea de definire a unor noi tipuri de date, de orice complexitate dar cu o utilizare similară tipurilor predefinite. De exemplu, o clasă de tip "stivă" va conține un vector (sau o listă înlănțuită) dar și operațiile asociate stivei: pune o valoare în stivă, scoate valoarea din vârful stivei, test dacă stiva este goală și inițializarea stivei. După ce s-a definit clasa "stivă" se pot declara variabile, parametri și chiar funcții de tip stivă.

Clasele (obiectele) din programe pot corespunde unor obiecte fizice, concrete din aplicație (cărți, automobile, piese mecanice, componente electronice, persoane umane, facturi, etc.) sau unor noțiuni abstracte, mai generale (om, animal, dată calendaristică, interval de timp, activitate).

Unii autori recomandă chiar extragerea părților de vorbire din descrierea aplicației și transformarea substantivelor în clase, adjectivelor în datele clasei și transformarea verbelor în funcții ale claselor (metodele clasei). De exemplu, clasa ce corespunde unei cărți dintr-o aplicație destinată unei biblioteci poate avea ca date titlul cărții, numele autorilor, anul apariției, prețul, etc., și ca operații asociate: împrumutarea la un cititor, restituirea la bibliotecă, ș.a.

Aceasta corespondență dintre componentele programului și noțiunile specifice aplicației este văzută ca un avantaj al POO, comparativ cu programarea tradițională, care înlocuiește universul problemei cu numere, șiruri de caractere, liste și operații cu variabile de aceste tipuri.

Avantajele principale ale POO pot fi rezumate astfel:

Utilizarea (și reutilizarea) unor module de program mai cuprinzătoare (clasele), organizate de multe ori ierarhic în familii (ierarhii) de clase; de aici, reducerea numărului de linii sursă care trebuie scrise pentru o nouă aplicație. Utilizarea unei clase C se face nu numai prin preluarea ei ca atare ci, mai ales, prin derivarea altor clase din C, cu adăugarea de funcții (și /sau date) necesare aplicației respective.

Reducerea posibilităților de eroare (programare mai sigură) datorită pe de-o parte faptului că toate clasele folosite au fost testate în prealabil și, pe de altă parte, verificărilor realizate de compilator asupra operațiilor cu obiecte (sunt permise numai operațiile prevăzute la definirea clasei respective).

Înțelegerea și întreținerea programelor mari este mai simplă datorită dimensiunii lor mai reduse și apropierii dintre elementele programului și noțiunile aplicației (problemei de rezolvat).

Pentru aprecierea acestor argumente este suficient să comparăm o aplicație Windows realizată cu clase ( de exemplu cu biblioteca MFC) cu aceeași aplicație realizată cu apeluri directe de funcții Windows (funcții API).

POO nu înseamnă doar folosirea altor construcții și tehnici în programare, ci presupune un alt mod de gândire și de abordare a programării (o proiectare orientată pe obiecte). În POO rezolvarea unei probleme se concentrează pe identificarea obiectelor, proprietăților și comportamentului lor și nu pe determinarea succesiunii operațiilor cu numere sau șiruri de caractere care conduc la soluția problemei. Ca și în cazul programării clasice, dificultatea cea mai mare o constituie analiza problemei și proiectarea (concepția) programelor și nu exprimarea proiectului în termenii unui anumit limbaj de programare.

2.3 Limbaje pentru programarea cu obiecte

Conceptele de bază și principiile programării orientate pe obiecte sunt aceleași pentru toate limbajele de programare "obiectuale", dar exprimarea acestor noțiuni abstracte în programe concrete trebuie să țină seama de particularitățile limbajului folosit.

În prezent, cele mai utilizate limbaje orientate pe obiecte sunt C++ și Java. Limbajul C++ a permis tranziția gradual de la programarea procedurală, structurată la programarea orientată pe obiecte. Mai mult, într-o aceeași aplicație C++ se pot folosi tehnici de programare aparținând ambelor stiluri.

Ulterior, s-a considerat că programele hibride (parțial procedurale și parțial obiectuale) nu sunt de dorit, astfel că limbajul Java impune o abordare exclusiv orientată pe obiecte a tuturor programelor ("abordare pur obiectuală").

Principalele avantaje ale limbajului C++ sunt:

Eficiența programelor executabile, ca lungime și ca timp de execuție.

Includerea limbajului C deci posibilitatea de a folosi cele mai adecvate tehnici de programare în diverse părți din aplicație și accesul nelimitat la facilitățile sistemului de operare.

Concizia exprimării, deci lungimea programelor sursă.

Principalele avantaje ale limbajului Java sunt:

Reunirea celor mai bune facilități din limbajele obiectuale anterioare și eliminarea unor aspecte mai nesigure sau discutabile din C++.

Posibilitatea utilizării ca limbaj de programare în Internet.

Existența unui mare număr de clase predefinite, standardizate și imediat utilizabile.

Un avantaj suplimentar pe care îl oferă Java unui începător în POO este și disponibilitatea surselor pentru clasele standard (JDK), care pot constitui bune exemple de definire și utilizare a unor clase, rezultat al muncii multor programatori.

2.4 Noțiuni de bază ale POO (programării orientate obiect)

Unitatea elementară a programelor orientate pe obiecte este obiectul. Limbajele care respectă conceptele programării orientate pe obiecte descriu relațiile dintre acestea. Toate obiectele au o stare și un comportament.

Starea unui obiect se referă la elementele de date conținute de obiect și la valorile asociate acestora. Tot ceea ce cunoaște obiectul despre aceste elemente și despre valorile lor formează starea obiectului. Elementele de date asociate obiectelor se numesc variabile de instanță. Comportamentul unui obiect depinde de acțiunile pe care obiectul poate să le execute asupra variabilelor de instanță definite în cadrul său. În programarea procedurală, o astfel de construcție se numește funcție. În terminologia specifică programării orientate pe obiecte, această construcție se numește metodă. O metodă aparține clasei a cărei membră este.

Astfel, starea unui obiect depinde de lucrurile pe care le cunoaște obiectul, iar comportamentul lui depinde de acțiunile pe care le poate executa. În cazul în care creăm un obiect software care reprezintă modelul unui televizor, obiectul va avea variabile care descriu starea curentă a televizorului, cum ar fi o variabilă care specifică dacă televizorul este pornit, precum și alte variabile care stochează canalul selectat, nivelul de volum și faptul că telecomanda nu transmite nimic pentru moment. De asemenea, obiectul va poseda metode care descriu acțiunile permise, cum ar fi pornirea și oprirea televizorului, schimbarea canalului, modificarea volumului și acceptarea comenzilor de la telecomandă.

Obiectele încapsulează variabile de instanță și metode înrudite într-o singură unitate identificabilă. Ca urmare, obiectele sunt ușor de refolosit, de actualizat și de întreținut. Un obiect poate apela una sau mai multe metode pentru executarea unei operațiuni. Metodele sunt inițiate prin transmiterea unui mesaj către obiectul respectiv. Un mesaj trebuie să conțină numele obiectului către care este transmis, numele metodelor care urmează să fie apelate și valorile necesare metodelor respective. Obiectul care recepționează mesajul folosește informațiile primite pentru a apela metodele corespunzătoare cu valorile specificate.

Avantajul încapsulării variabilelor de instanță și a metodelor constă în faptul că putem trimite mesaje unui obiect, fără să cunoaștem modul de lucru al obiectului respectiv.

Clasele încapsulează obiecte. O singură clasă poate fi folosită pentru instanțierea mai multor obiecte. Aceasta înseamnă că putem avea mai multe obiecte active sau mai multe instanțe ale aceleiași clase.

Noțiunea de "clasă" poate fi privită ca o generalizare și o abstractizare a unui grup de obiecte care au în comun anumite proprietăți (atribute) ai acțiunii (operații). Un obiect este, în acest caz, o "instanțiere" a unei clase, deci un caz particular concret de clasă.

De exemplu, se poate defini un nou tip de date, cum ar fi tipul "complex" sub forma unei clase care reunește cele două componente ale unui număr complex cu operațiile uzuale asupra numerelor complexe: operații aritmetice, operații de citire /scriere, etc. Un obiect din clasa "Complex" va avea valori numerice pentru partea reală și pentru partea imaginară și va putea fi prelucrat prin metodele specifice clasei "Complex".

Situația descrisă este cea mai des întâlnită în POO și corespunde claselor ce pot fi instanțiate, deci care pot genera obiecte.

În C++ și în alte limbaje de programare, o colecție de clase sau de funcții înrudite formează o bibliotecă. Java pune o amprentă proprie asupra bibliotecilor, folosind termenul de pachet pentru descrierea unei colecții de clase înrudite. Așa cum clasele încapsulează obiecte, pachetele încapsulează clase.

O metodă a unei clase instanțiabile este o funcție apelată pentru un anumit obiect, deci este întotdeauna asociată unui obiect concret.

În Java, toate funcțiile sunt metode ale unor clase, deci o metodă poate fi apelată numai dintr-o altă metodă. Atunci când o metodă a unei clase A apelează o metodă a unei clase B se mai spune că un obiect din clasa A transmite un mesaj unui obiect din clasa B, prin care i se cere o anumită operație.

De exemplu, o clasă de obiecte grafice conține metode de afișare pe ecran, de schimbare a poziției sau dimensiunilor; o altă clasă poate deci transmite unui obiect grafic mesaje de tipul "afișează-te" sau "mută-te în altă poziție" sau "modifică-ți dimensiunile".

Moștenirea este o caracteristică puternică a limbajelor de programare orientate pe obiecte, care permite să refolosim codul și să extindem funcționalitatea claselor existente. Folosind acest aspect al programării orientate pe obiecte, putem crea o nouă clasă care moștenește funcționalitatea unei clase existente. Putem apoi să extindem funcțiile vechii clase, astfel încât să corespundă necesităților curente.

O (sub)clasă derivată dintr-o clasă instanțiabilă moștenește de la aceasta date și metode (operații), pe care le poate modifica sau la care poate adăuga alte date și /sau metode proprii.

În terminologia Java, o subclasă "extinde" o altă clasă (superclasa ei), în sensul că adaugă superclasei noi funcții, deci o extinde ca operații posibile. În același timp însă, o subclasă este mai specializată, mai puțin generală decât superclasa ei. O subclasă D este un anumit caz particular de superclasă C. Se mai spune că D este un fel de C.

De exemplu, o clasă "fereastră" (Window) este o clasă mai generală, dar din ea pot fi specializate diferite tipuri de ferestre: buton, fereastră în care se afișează un text nemodificabil, fereastră de dialog, fereastră cu o listă din care se poate selecta un element, etc.

Există însă și clase abstracte, care nu pot fi instanțiate, dar care pot fi folosite pentru obținerea prin derivare a unor clase instanțiabile. O clasă abstractă este o clasă cu sau fără date, dar pentru care o parte din metode (sau toate) sunt metode abstracte. O metodă abstractă este declarată (anunțată) ca rol, tip și parametri, dar nu este definită printr-o secvență de instrucțiuni. Pentru o metodă abstractă se știe ce trebuie să facă dar nu se știe (încă) cum trebuie să facă. Subclasele derivate dintr-o clasă abstractă vor trebui să precizeze metodele abstracte moștenite.

O subclasă a unei clase abstracte moștenește doar obligația de a implementa metodele abstracte.

De exemplu, clasa "Applet" din Java este o clasă abstractă, din care se vor deriva toate clasele ce corespund unor aplicații particulare, numite "applet-uri" și care pot fi executate numai pornind de la un fișier HTML.

În Java se mai întâlnesc și clase care nu sunt abstracte dar nici nu sunt instanțiabile; acestea sunt clase care conțin numai metode statice (și, mai rar, date statice) și care au rolul de a reuni mai multe funcții, care nu operează însă asupra unor date comune. Aceste clase corespund unor biblioteci de funcții cu caracter general, a căror utilizare nu este condiționată de existența unor anumite obiecte.

De exemplu, clasa "Math" din Java reunește funcții matematice uzuale ce operează cu date de tipul primitiv "double" și a căror folosire nu este legată de existența unor obiecte din alte clase.

Capitolul III.

Prezentarea Limbajului de programare Java

Rădăcinile limbajului Java se află într-un proiect de cercetare (proiectul “Green”) al firmei Sun. Coordonator de proiect era James Gosling, unul din veteranii designului software-ului de rețea.

Java nu este numai un limbaj de programare, Java este un mediu de programare ce oferă utilizatorului cadrul necesar și uneltele necesare dezvoltării aplicațiilor Java. Java este o tehnologie care oferă suport dezvoltării de aplicații distribuite, independente de platformă. Programele Java pot rula pe diferite tipuri de platformă, cu condiția să existe instalată o mașina virtuală Java deasupra platformei respective .

Cea mai mare parte a sintaxei de programare Java este moștenită din C++, dar multe din conceptele de programare obiectuală prezentate în Java își au rădăcinile în SmallTalk, Lisp etc. Arhitecții de la Sun au inclus în acest limbaj cele mai noi concepte de programare făcându-l o unealtă puternică și ușor de manevrat.

3.1 De am ales limbajul Java

Limbajul Java are câteva caracteristici care l-au făcut și-l fac un limbaj de succes pe piața actuală de software , piață în care tehnologia apare și dispare de la o zi la alta.

Un prim argument în favoarea folosirii limbajului Java este simplitatea lui, conceptele fundamentale ale limbajului fiind foarte simple. Fără a pierde din puterea limbajului, designerii lui au renunțat la părțile redundante ale unui limbaj, păstrând doar părțile strict necesare . Tot în ideea simplității, tehnologia Java conține așa numitul Garbage Colector, care eliberează programatorul de grija dezalocării zonelor de memorie alocate . Pentru cei familiari cu C++ , acest lucru înseamnă că nu mai e nevoie de delete după new . Garbage colectorul este supraveghetorul din umbră care face curățenie după noi, scăpându-ne de grija eliberării memoriei, de date care nu ne mai trebuie.

Faptul că respectă o mare parte a gramaticii, sintaxei de programare C/C++ face să poată fi ușor de învățat de cei care au lucrat în limbajul C/C++ .

Un alt argument este faptul că spre deosebire de C++ limbajul java este în întregime bazat pe obiecte. Tehnologia programării orientate pe obiecte (OOP-Object Oriented Programming) este singura care satisface cerințele actuale de dezvoltare software. Gradul de intercomunicare între echipele de programatori se mărește considerabil, depanarea, modificarea codului se face într-un timp mult mai scurt rezultând o eficiență mult crescută a dezvoltării sistemelor software, deci în ultimă instanță un preț mai scăzut.

Java mărește gradul de siguranță al codului. Există doua nivele de verificare: unul la compilare (prezent în marea majoritate a limbajelor) și unul la rulare. Ca urmare, un program este mai puțin supus erorilor. Comparativ cu C++, multe din trăsăturile acestuia care de foarte multe ori erau surse de erori, au fost eliminate (pointerii de exemplu au fost eliminați). Accesul la tablourile Java este verificat și la rulare, eliminând astfel posibilitatea accesului accidental sau malițios în afara domeniului tabloului. Conversiile între tipurile de date sunt limitate, evitându-se astfel scrierea nepermisă a unor zone de memorie.

Intr-o lume în care calculatoarele nu mai pot exista ca entități solitare, fără a fi conectate în rețea, problema securității este una din cele mai stringente. Se pune problema existenței unui nivel de securitate în cadrul limbajului. Gradul de securitate mărit este unul din principalele avantaje ale limbajului Java care l-au făcut atât de popular. Programele Java sunt făcute să ruleze în sisteme distribuite, calculatoarele pe care ele lucrează nu pot fi sigure de proveniența programelor. Ca urmare, trebuie oprit accesul acestor programe la unele resurse locale pentru a preveni eventualele acțiuni malițioase. În vederea acestui lucru există mai multe proceduri de verificare. Pe lângă verificările de la compilare există verificările de la execuție. Programele Java sunt verificate pas cu pas în timpul rulării prevenind accesul în zonele nepermise. Acest lucru însă nu este fezabil dacă nu era rezolvată problema accesului în afara tablourilor sau problema conversiilor nepermise. Ca urmare există mai multe nivele de securitate în Java.

Un alt argument ar fi acela că Java este un limbaj dinamic prin faptul că multe decizii privind evoluția programului se iau în momentul rulării, la runtime. Dat fiind faptul că multe din aplicațiile Java sunt preluate de pe Internet sub formă de applet-uri chiar în momentul execuției lor, deci în rețea, aceste programe pot fi actualizate să facă față noilor cerințe, utilizatorul dispunând în orice moment de cea mai nouă variantă.

Unul din marile avantaje ale limbajului Java este faptul că este independent de platformă. Într-o lume în care fiecare mare companie de software încearcă să monopolizeze piața forțând o dependență de sistemele hardware, de sistemele de operare, de propriile standarde, Java aduce un aer proaspăt de cooperare, de limbaj viabil pentru toate platformele. Această independență de platformă se impunea, ținând cont de ideea de lucru în sisteme distribuite. De fapt un program Java lucrează pe o singură mașină: mașina virtuală Java (Java Virtual Machine-JVM). Aceasta este o platformă virtuală transpusă în realitate prin intermediul interpretorului, mai exact a emulatorului Java. Este un emulator pentru că se emulează execuția unui program în cadrul unei mașini Java, și nu se transformă codul Java pur și simplu în cod mașină ca in cazul unui interpretor. Programele executabile Java, numite și bytecodes sunt rezultatul compilării unui program text. Pentru a putea fi executate pe o anumită platformă (Windows, Unix) acestea au nevoie de un emulator Java Virtual Machine specific respectivei platforme. Emulatorul convertește bytecodul java în cod executabil pe mașina reală pas cu pas, instrucțiune cu instrucțiune. Ca urmare a utilizării emulatorului un program Java poate rula pe orice platformă pentru care există un emulator Java. Problema utilizării emulatorului este însă cu două tăișuri. Partea negativă este că folosirea emulatorului duce la mărirea timpului de execuție. Soluția este compilarea just-in-time (JIT) care transformă întregul program Java în program mașină înainte de execuția lui. Compilatoarele just-in-time lucrează ca și interpretoarele doar că conversia nu se face la nivel de instrucțiune ci doar la nivel de program, crescând considerabil viteza de execuție a programului Java.

Java are si suport pentru multithreading ceea ce constituie un avantaj. Multithreading-ul este cel care permite ca un program să execute mai multe sarcini aparent în același timp, utilizând mai multe fire de execuție (thread-uri). Java oferă suport pentru multithreading la nivel de limbaj deci la cel mai jos nivel (clasa Thread) oferindu-i astfel utilizatorului posibilitatea de a crea un nou fir de execuție ca și cum ar crea oricare alt obiect. Mai mult, Java permite comunicarea între fire de execuție precum și sincronizarea lor.

Unul din principalele avantaje care a făcut limbajul Java așa de popular este interconexiunea cu browser-ele www. Multe din firmele care dezvoltă browser-ele www au implementat mașina virtuală Java în interiorul acestor browsere. Un browser compatibil Java permite ca o categorie specială de aplicații, numite applet-uri să fie transformate de la server-ul www pentru a fi executate la client, adică pe calculatorul unde se execută browser-ul www. Conexiunea browser-ului cu applet-urile se face prin intermediul etichetelor html, html fiind limbajul în care se scrie o pagină web.

3.2 Arhitectura Limbajului Java

Mediul de execuție al limbajului Java, numit și Java Runtime Environment (JRE), reprezintă cadrul de execuție al unui program Java, al unui bytecode Java. După cum se vede în figura 3.1, pentru a executa un program Java se trece prin mai multe etape. În primul rând este nevoie de un program sursă (cu extensia java). Acesta este compilat (utilizând un compilator java, de exemplu javac) obținându-se un fișier executabil Java, un bytecode Java. Acesta poate fi executat doar în contextul unui mediu de execuție Java, un JRE, prin apelul unui emulator-interpretor (exemplu: programul java din mediul jdk).

Fig.3.1. Crearea și execuția unui program Java

Mediul de execuție al Java, JRE, nu poate executa un program Java fără să conțină două componente importante (figura 3.2). Aceste două componente sunt parte librăriile (package-urile) Java și pe de altă parte mașina virtuală Java (JVM).

Fig. 3.2. Ierarhia mediului de execuție Java

Structura mașinii virtuale Java (Java Virtual Machine – JVM) este prezentată în figura următoare:

Fig. 3.3. Structura mașinii virtuale Java

Legat de această structură prezentăm pe scurt componentele mașinii virtuale Java:

Class Loader – Este utilizat pentru a aduce fișierele bytecode (.class) necesare execuției programului. Aceste fișiere se pot găsi pe orice calculator dintr-o rețea.

Bytecode Verifier – Este componenta JVM care se ocupă de verificarea fișierelor bytecode pentru ca acestea să respecte setul de reguli Java. Dacă un fișier nu se conformează acestor reguli este respins.

Odată verificat, programul Java este gata de execuție. Execuția se poate face prin intermediul unui interpretor-emulator sau prin intermediul unui compilator Just In Time (JIT). Prin emulator execuția fiecărei instrucțiuni Java este emulată într-o JVM, ceea ce impune un nivel suplimentar deasupra platformei de lucru. Acest lucru se întâmplă în momentul execuției programului ceea ce duce la un consum mare de timp de procesare. În cazul utilizării compilatorului JIT, acesta transformă, din primul moment, întreg programul Java în instrucțiuni procesor ceea ce duce la mărirea vitezei de execuție a programului.

Garbage Colectarul – Este componenta ce se ocupă de eliberarea zonelor de memorie alocate și care nu mai sunt utilizate de program. Acest lucru ia de pe capul programatorului grija dezalocărilor de memorie. Specificațiile mașinii virtuale Java nu impun însă un anumit algoritm de dezalocare, lăsând la latitudinea celui ce implementează JVM stabilirea lui.

Security Manager – Este componenta ce asigură respectarea unor restricții de securitate impuse de lucrul în sistemele deschise. Lucrează împreună cu mai toate celelalte componente ale JVM.

3.3. Applet-uri și aplicații

3.3.1 Dezvoltarea și execuția applet-urilor și aplicațiilor

Termenul de aplicație Java se referă la un program care poate fi folosit în mod independent. Aplicațiile Java nu necesită un program de vizualizare extern și se folosește direct interpretorul Java.

Procesul de creare și lansare în execuție a unei aplicații Java implică mai multe operații: mai întâi trebuie să scriem codul și să-l salvăm într-un fișier cu extensia “.java” , apoi trebuie să compilăm programul editat prin comanda “javac <nume_fișier>.java” obținându-se un nou fișier “<nume_fișier>.class”,fișier ce conține programul executabil (bytecode) Java și în ultimul rând trebuie să lansăm în execuție programul prin comanda “java <nume_fișier>.class” .

O aplicație Java conține o singură clasă (publică), care trebuie obligatoriu să conțină metoda main care este apelată la lansarea în execuție a programului. Metoda main este de fapt o funcție (similară cu funcțiile C) care primește ca parametrii un vector de șiruri de caractere reprezentând argumentele din linia de comandă cu care a fost lansat programul. În Java șirurile de caractere sunt (ca toate datele de altfel) obiecte aparținând clasei String. Un vector de astfel de obiecte este definit ca String[]. Această funcție trebuie să fie accesibilă din exteriorul obiectului pentru ca interpretorul să poată cere execuția acesteia, să fie publică, motiv pentru care este declarată de tip public. Codul acestei funcții este comun tuturor instanțelor clasei, metoda fiind declarată din acest motiv static. De asemenea main nu întoarce nimic fiind deci declarată void. În general, numele unei metode statice trebuie precedate de numele clasei din care face parte (separate prin punct), dar care nu este apelată dintr-o metodă din aceeași clasă.

Termenul de applet Java (miniaplicație) se referă, în general, la un mic program Java, creat pentru a fi folosit în sistemul World Wide Web. Miniaplicațiile Java necesită un program de vizualizare extern, așa încât, pentru a putea folosi o miniaplicație, avem nevoie de un browser Web sau de un program specializat de vizualizare (applet viewer). În vederea acestei execuții în interiorul unui browser, se creează un fișier html care se conectează prin intermediul unui tag html de programul Java obținut după compilare.

Procesul de creare și lansare în execuție este asemănător cu cel de la aplicație cu deosebirea că în etapele de dezvoltare ale unui applet se adaugă scrierea fișierului html. Procesul dezvoltării și execuției unui applet (fig.3.4) începe cu editarea unui applet java. Prima condiție ce trebuie impusă este ca programul să conțină o clasă publică, cu numele identic cu numele fișierului, clasă care trebuie derivată din clasa Applet (derivarea se face prin cuvântul cheie extends). Pentru a putea utiliza clasa Applet în derivare trebuie să specificăm utilizarea ei sau întregului pachet din care face parte (java.applet). În mod obligatoriu un applet trebuie să conțină una din metodele paint(), init(), sau start(). Una din aceste metode este apelată de browser pentru afișarea applet-ului în pagina html.

Fig. 3.4. Procesul dezvoltării și execuției unui applet Java

Următorul pas este compilarea applet-ului Java care se face la fel ca la o aplicație stand-alone, prin utilitarul “javac <nume_fișier>.java”. Apoi trebuie să creăm o pagina html care să conțină legătura cu programul Java, legătură ce se face prin intermediul tag-ului APPLET de forma “<APPLET…>…</APPLET>”. Acest tag trebuie să conțină în mod obligatoriu atributele CODE=”numeApplet.class”, atribut ce anunță browser-ul că trebuie să pornească JVM executând programul în care se află fișierul “numeApplet.class” din directorul în care se află fișierul html curent, WIDTH și HEIGHT atribute ce specifică dimensiunea applet-ului. În ultima fază trebuie să lansăm în execuție applet-ul prin comanda “appletviewer <nume_pagină>.html” sau încărcând pagina html utilizând un browser www compatibil. Teoretic un applet are asociat un flux de intrare și unul de ieșire, dar este foarte probabil ca acestea să fie ascunse utilizatorului de către programul de navigare, deci applet-ul nu trebuie să le folosească.

Într-o primă fază browser-ul, clientul www, la indicația utilizatorului se va conecta la un server www de unde va cere o pagină html. Comunicația se face pe baza protocolului http(Hyper Text Transfer Protocol) într-un nivel http aflat deasupra nivelelor TCP/IP. Odată pagina html primită de browser acesta o va afișa într-un anume format. În cazul în care pagina conține un tag de tip APPLET se pornește mașina virtuală Java-JVM. Cunoscând locația fișierului .class care conține programul applet, din atributul CODE, JVM cere server-ului www clasa applet-ului. Acest din urmă transfer se face tot pe baza unui protocol http. După ce a primit clasa applet de la server, JVM pornește execuția ei. În cazul în care în execuția programului e nevoie și de alte clase disponibile doar la server (altele decât cele din Java Core API de care JVM dispune la client) JVM va cere aducerea lor. Această cerere se face doar în momentul în care e nevoie de ele.

3.4 Aplicații de rețea. Socluri (Sockets)

Java a câștigat teren în fața competitorilor prin capacitatea de adaptare la mediul eterogen de procesare oferit de o rețea de calculatoare. Această capacitate nu este realizată numai prin faptul că este limbaj independent de arhitectura hardware pe care se execută, ci și prin facilitățile speciale pe care le oferă pentru dezvoltarea unor aplicații distribuite, care folosesc ca mediu de comunicare Internet-ul.

Java este proiectat ca un limbaj de programare pentru rețele. Din acest motiv, suportul pentru aplicațiile care folosesc rețeaua pentru a comunica este de foarte bună calitate. În aceeași idee a păstrării unei legături cu programele deja dezvoltate și compatibilității cu standardele existente (oficiale sau de facto), Java oferă în cadrul modulului java.net clase care prezintă o nouă haină interfeței mai vechi de programare cunoscută în lumea rețelelor IP ca interfața bazată pe socluri (sockets). Aceste clase, numite clase soclu, creează o interfață elegantă și flexibilă, făcând programarea aplicațiilor pentru rețelele IP la fel de ușoară ca lucrul cu fișiere.

Trebuie remarcat că interfața de programare cu socluri oferită de Java permite comunicarea cu alte programe care folosesc o interfață de tip soclu, scrise de exemplu în limbajul C. Aceasta este, de altfel, una din modalitățile prin care Java poate să comunice cu aplicații deja existente, scrise în alte limbaje de programare.

Soclurile sunt un nivel de abstractizare dezvoltat la Universitatea Berkeley din California, SUA, pentru a permite o programare ușoară a rețelelor de calculatoare. Teoretic, această interfață este independentă de protocoalele de comunicație folosite, dar în practică este legată de protocoalele suitei TCP/IP. Implementări ale acestei interfețe se pot găsi nu numai în sistemele de operare UNIX, dar și în orice sistem de operare care permite conectivitate TCP/IP. De exemplu, în sistemele de operare Windows există o versiune a acestei interfețe numită WinSock. Existența acestei interfețe în majoritatea sistemelor de operare a făcut posibilă portarea ușoară a programelor care folosesc rețelele IP, ducând la o largă răspândire a acestor programe.

Înainte de a vorbi despre aplicațiile client-server și implicit despre socket-uri vom vorbi despre utilizarea obiectelor adresă IP și despre comunicarea prin protocoale orientate pe conexiune.

Utilizarea obiectelor adresă IP

Orice calculator gazdă conectat la Internet trebuie să aibă o adresă pentru a fi identificat. Aceste adrese se numesc adrese IP, după numele protocolului care folosește astfel de adrese. Adresele IP sunt formate din numere compuse din 4 octeți, iar reprezentarea lor se face separând cu punct cei patru octeți care compun adresa (un exemplu de adresă IP este 127.0.0.1). Deoarece acest mod este greu de folosit, s-a introdus suplimentar un sistem simbolic de adresare a gazdelor. Deoarece programele IP folosesc numai adrese numerice, iar utilizatorii, de obicei, numai adrese simbolice, trebuie să existe un mecanism care să permită realizarea conversiei între cele două sisteme de adresare. În Java, acest mecanism este realizat prin intermediul unui obiect din clasa InetAddress. Aceste obiecte reprezintă adrese IP și oferă posibilitatea realizării translației între cele două tipuri de adrese. Metoda statică getLocalHost() are ca rezultat un obiect care instanțiază clasa InetAddress, obiect care este instanțiat cu adresa stației curente. Extragerea corespondentului simbolic al adresei se face prin apelul metodei getHostName(), al cărei rezultat este un șir de caractere identic cu numele simbolic al stației.

În Internet există calculatoare care au mai multe adrese IP. Aceasta este rezultatul unei reguli care spune că același calculator trebuie să aibă câte o adresă IP pentru fiecare rețea în care este conectat.

Obținerea unui obiect din clasa InetAddress nu se face prin apelul unui constructor, ci prin intermediul unor metode statice (getLocalHost(), getByName(), getAllByName()), care apelează unul din constructorii privați ai obiectului și au ca rezultat un obiect (sau un vector de obiecte) din clasa InetAddress.

Existența unui constructor public este necesară în special în cazul acțiunii de moștenire, atunci când obiectul este nevoit să-și inițializeze superclasa. În versiune 1.1 a pachetului de dezvoltare Java, clasa InetAddress este declarată final. Deoarece obiectele acestei clase nu pot fi extinse prin moștenire, proiectanții au preferat să folosească inițializarea prin metode statice , deoarece funcțiile cu nume asemănător sunt de mult folosite în cadrul bibliotecii standard C de programare a aplicațiilor de rețea.

Cele mai multe aplicații care folosesc comunicația prin rețea au nevoie de stabilirea unui canal sigur de comunicație, astfel încât să aibă certitudinea că mesajele pe care le trimit ajung corect și în aceeași ordine la partener. Majoritatea protocoalelor care oferă acest serviciu folosesc conexiuni pentru stabilirea acestui canal sigur, de unde și numele de protocoale orientate pe conexiuni. Odată stabilită conexiunea, aplicațiile pot folosi canalul de comunicație prin intermediul abstractizării oferite de fluxurile de date (streams). Astfel, un canal implementează două fluxuri de date unidirecționale, fiecare flux fiind folosit pentru comunicarea într-un singur sens. Este treaba programelor de sistem care gestionează comunicația în rețea (și nu a programatorului de aplicații) să asigure siguranța în funcționare specifică conexiunilor. La fiecare capăt al acestui canal există un soclu care permite trimiterea datelor prin acesta și recepția informațiilor trimise prin către și de la stația parteneră. Orice conexiune este unic determinată de cele două socluri plasate la cele două capete ale conexiune. Pentru a putea transmite date în siguranță, programatorul trebuie doar să specifice adresa aplicației partener, cu care dorește să comunice, programele de sistem asigurând stabilirea conexiunii și gestiunea acesteia.

Aplicațiile de rețea comunică după schema client – server. Aplicația server oferă servicii aplicațiilor client. Pentru a obține un serviciu de la o aplicație server, aplicația client trebuie să se conecteze la aplicația server, între cele două stabilindu-se un canal virtual de comunicație. Aplicația server așteaptă cereri de conectare de la aplicațiile client “ascultând” un port TCP prestabilit n. În momentul în care apare o cerere de conectare din partea unei aplicații pe portul n al calculatorului pe care rulează aplicația server, aceasta recepționează cererea și poate să o accepte deschizând un canal de comunicație duplex pe portul n. Odată creat acest canal, aplicația client poate să-i transmită serverului mesaje-cereri de servicii. Serverul răspunde aplicației client rezultatul procesărilor solicitate prin mesajele-cerere. La terminarea servirii, serverul sau clientul pot închide canalul de comunicație virtual.

Elementul central în crearea și gestionarea unui canal virtual de comunicație între două aplicații este soclul (socket). Acesta este asemănător unui specificator (handler) de fișier fiind un număr întreg pozitiv care identifică unul din cele două puncte terminale al unui canal de comunicație virtuale. Datele transmise pe acest canal sunt buffer-izate atât de aplicația server care transmite datele cât și de aplicația client care le recepționează. Soclul nu este tot una cu portul TCP. Mai curând este un specificator de acces la date care include atât adresa de IP cât și portul prin care se realizează comunicația, caracterizând canalul de comunicație virtuală.

3.4.1 Comunicare prin protocoale orientate pe conexiune

Un protocol este o combinație de reguli de comunicație și formate de mesaje care trebuie respectate de calculatoarele legate în rețea pentru a schimba date. Scopul primar al protocoalelor este de a permite comunicația între calculatoare, indiferent de rețea sau de hardware-ul calculatoarelor legate în rețea.

O conexiune reprezintă un canal sigur de comunicație în rețea, stabilit de către un protocol pentru transmiterea corectă și în ordine a mesajelor între calculatoare. O conexiune este formată din două fluxuri de date unidirecționale folosite pentru comunicație precum și din două socluri (socket) care permit trimiterea, respectiv recepția datelor. Orice conexiune este unic determinată de cele două socluri plasate la cele două capete ale conexiunii.

Orice conexiune trece prin trei faze de-a lungul vieții sale, prima fază este crearea soclurilor de la capetele conexiunii, rămânând în sarcina programelor de sistem stabilirea conexiunii între cele două socluri. Dacă operația de creare a soclurilor a reușit, programatorul poate, din acel moment, să obțină referințe către două fluxuri de date (trimitere și recepție), fluxuri asociate capătului său de conexiune. Cele două fluxuri de date vor fi folosite pentru comunicarea cu aplicația partener. După încheierea comunicației prin canal, fiecare partener trebuie să închidă soclul său, realizându-se astfel distrugerea conexiunii.

Figura 3.4. Transmiterea soclurilor prin canalele de comunicație.

În cadrul implementării standard Java, protocolul folosit pentru implementarea comunicației sigure pe bază de conexiuni este TCP (Transmission Control Protocol), unul din protocoalele de bază ale familiei TCP/IP. Acest protocol asigură o comunicare sigură, cu prețul stabilirii de conexiuni înainte de transmisie și al unei rate de transfer mai mici datorată mesajelor de confirmare.

Modul de lucru cu soclurile se încadrează în modelul client /server de scriere de aplicații. În cadrul acestui model, aplicațiile se împart în două categorii :

programe client – cele care inițiază conversația

programe server – cele care oferă servicii programelor client

Există un singur server pentru mai mulți clienți, deci serverul trebuie să aibă un mod de a face diferența între clienții pe care-i servește la un moment dat. Clientul este un program care se bazează în funcționarea sa pe serviciile pe care le oferă un program server.

Trebuie remarcat că soclurile de la capetele unei conexiuni sunt identice, dar sunt create în moduri diferite. Asimetria este dată de modul de stabilire a unei conexiuni: un program, numit client, creează un soclu căruia îi specifică adresa programului partener. În cadru inițializării soclului, sistemul trimite o cerere de conexiune către programul cu care clientul dorește să comunice, program numit server. Programul server este pregătit să primească cereri de conexiune, iar la acceptarea unei cereri de conexiune programele de sistem creează soclul pereche, soclu pe care programatorul aplicației partener îl primește ca rezultat al acceptării conexiunii. În același timp, sistemul de pe calculatorul server trimite sistemul client un mesaj de confirmare a stabilirii conexiunii, moment în care inițializarea soclului client se încheie. Așadar, în programul client, soclul este creat explicit, iar în programul server acesta este creat implicit de către biblioteca de funcții.

Pentru a realiza comunicarea cu un server, clientul are nevoie de două informații care compun împreună adresa serverului: numele gazdei pe care rulează serverul și numărul de port pe care serverul ascultă cereri de conexiuni.

Orice conexiune între două programe care comunică prin rețea este determinată unic de 4 elemente :

adresa gazdei pe care rulează aplicația client;

numărul de port al aplicației client;

adresa gazdei pe care rulează aplicația server;

numărul de port pe care serverul primește cererile;

Un soclu Java poate lucra în două moduri :

direct – implicit (suficient pentru majoritatea aplicațiilor)

cu facilități speciale pe soclu, folosit de aplicațiile care necesită comunicarea peste un zid de protecție (firewall) sau prin intermediul unui server proxy.

3.4.2 Funcționarea soclurilor de tip conexiune

Comportamentul soclurilor de tip conexiune poate fi modificat prin intermediul unor opțiuni. Unele din aceste opțiuni sunt preluate dintre cele standard pentru soclurile clasice (de exemplu opțiunile SO_LINGER și TCP_NODELAY, definite prin API-ul socket), iar altele sunt introduse pentru a ușura munca programatorilor (cazul opțiunii SO_TIMEOUT). Deși valorile implicite sunt bine alese pentru majoritatea aplicațiilor, o bună înțelegere a semnificației opțiunilor poate ajuta programatorul în obținerea de performanțe.

Pentru toate cele trei opțiuni definite în JDK 1.1 sunt furnizate două metode: una pentru aflarea valorii curente a opțiunii (metodă formată din numele opțiunii și prefixul get) și o alta pentru stabilirea unei noi valori a opțiunii (numele opțiunii prefixat de set).

Cea mai folosită opțiune este SO_TIMEOUT, opțiune care asigură deblocarea operațiilor recepție (în cazul soclurilor pentru comunicare – Socket) sau acceptare de conexiuni (în cazul soclurilor pentru acceptarea conexiunilor – ServerSocket). În mod implicit, aceste operații se blochează infinit, până când operația se termină normal sau până când apare o eroare. Deși există mecanisme pentru a împiedica blocarea infinită, chiar în absența opțiunii SO_TIMEOUT, existența unui mecanism la nivelul soclurilor face programarea mai ușoară și mai eficientă. Valoarea curentă poate fi aflată prin apelul metodei getSoTimeout(), iar modificarea prin apelul metodei setSoTimeout(). Valoarea implicită a acestei opțiuni este 0, valoare care inhibă deblocarea automată. Intervalul de timp ce poate fi stabilit, măsurat în milisecunde, este reprezentat de o valoare pozitivă reprezentată pe un întreg, ceea ce înseamnă că deblocarea poate fi planificată după trecerea unui interval de timp cuprins între 1ms și aproape 25 zile. În cazul în care deblocarea unei operații s-a produs ca urmare a expirării intervalului de timp stabilit se semnalează o excepție de tip java.io.InterruptedIOException. Captarea acestei excepții asigură programatorului mijlocul de detectare a modului în care s-a terminat operația analizată. Pentru a proteja o operație contra blocării infinite, programatorul trebuie să activeze opțiunea SO_TIMEOUT înainte de operația care poate produce blocare. Opțiunea nu este dezactivată de operațiile blocante, ceea ce înseamnă că, odată stabilită, opțiunea este luată în considerare de toate metodele ulterioare care se pot bloca.

O altă utilizare a opțiunii SO_TIMEOUT este implementarea unui mecanism de multiplexare a mai multor socluri. Să considerăm cazul unei aplicații în care programatorul trebuie să monitorizeze mai multe socluri de ascultare conexiuni, create pe porturi diferite. În cazul în care resursele nu permit crearea de fire de execuție care să se ocupe individual, de fiecare soclu în parte, putem folosi opțiunea SO_TIMEOUT pentru a analiza starea fiecărui soclu, pentru un interval de timp foarte scurt. De exemplu, dacă avem de monitorizat 7 socluri de ascultare conexiuni și dacă dorim ca fiecare soclu să fie analizat cel puțin odată la 2 secunde, stabilim opțiunea SO_TIMEOUT la o valoare cel mult egală cu 285 milisecunde, fiind deblocați după trecerea acestui interval de timp (sau la stabilirea unei conexiuni), moment în care putem trece la analiza următorului soclu de ascultare.

Mai avem o problema cu pachetele care au fost trimise înainte de închiderea unui soclu de comunicare, dar pe care sistemul nu a apucat să le trimită înainte de execuția metodei de închidere a conexiunii. Opțiunea SO_LINGER guvernează modul în care sunt tratate aceste pachete. Ea este implicit dezactivată, iar pentru schimbarea opțiunii se folosește setSoLinger(). Metoda primește ca parametrii o valoare logică, care stabilește dacă opțiunea este activată sau nu, și un întreg care stabilește un interval de timp în secunde, interval care va fi folosit pentru a aștepta trimiterea datelor rămase. Deși nu există o valoare care să specifice o așteptare blocantă până când s-au transmis toate datele rămase, utilizatorul poate implementa o așteptare blocantă prin folosirea unui interval de timp suficient de mare.

Informarea asupra stării curente a opțiunii SO_LINGER se face prin metoda getSoLinger(), care are ca rezultat valoarea intervalului de timp de așteptare, în secunde, sau –1 în cazul în care opțiunea este dezactivată.

Una din optimizările frecvent folosite pentru creșterea performanțelor comunicației folosind TCP este strângerea mai multor pachete mici care trebuie transmise la momente de timp apropiate în cadrul unui singur pachet mai mare. Algoritmul care realizează această conglomerare a pachetelor este cunoscut sub numele de algoritmul lui Nagle, iar opțiunea care activează sau nu folosirea acestui algoritm este TCP_NODELAY. În cazul în care aplicația care folosește comunicația prin TCP nu este sensibilă la mici întârzieri ale pachetelor, se recomandă activarea opțiunii prin folosirea metodei setTcpDelay(false), mai ales în cazul în care comunicația între client și server nu se desfășoară după modelul întrebare-răspuns (caz în care este bine ca pachetele să plece cât mai repede din nodul care le-a emis). Starea implicită a acestei opțiuni se află cu metoda getTcpDelay().

3.4.3 Aplicații client-server

Clasa Socket este obiectul de bază în comunicația Internet. Instanțele ei sunt cele care permit unui program client să inițieze o conexiune (prin intermediul constructorului) și să implementeze comunicația prin rețea între programe. Obiectele clasei Socket pot avea un comportament modificat față de cel standard, modificare realizându-se prin modificarea setului de metode descrise de clasa abstractă SocketImpl. Comportamentul standard al soclurilor le permite comunicarea în Internet fără restricții impuse de ziduri de protecție sau mecanisme criptografice. Orice comportament diferit de cel standard trebuie scris explicit de programator prin intermediul unei noi clase derivate din SocketImpl.

Clasa Socket abstractizează noțiunea de soclu client (numit în general soclu) și este responsabilă de majoritatea operațiilor necesare comunicației în rețea. Prin instanțierea unui obiect de tip Socket, programul client poate să inițieze o conexiune (prin constructor) și să implementeze comunicația prin rețea.

Constructorul clasei Socket este cel care implementează funcția de stabilire a comunicației cu aplicația partener. Există mai multe variante de constructori. Pentru identificarea calculatorului gazdă a aplicației cu care se realizează conexiunea se folosește fie un șir de caractere (identic cu numele simbolic al gazdei aplicației), fie un obiect corespunzător din clasa InetAddress. Numărul de port pe care ascultă aplicația server este specificat ca al doilea parametru. Acest număr specifică numărul de port de pe calculatorul partener (numărul de port care va fi atribuit local soclului creat, ce poate fi aflat prin apelul metodei getLocalPort()).

La crearea unui obiect din clasa Socket se deschide un canal virtual de comunicație duplex între aplicația client de pe calculatorul local și aplicația server de pe calculatorul corespondent. Clasa Socket definește metode care permit scrierea /citirea în /din canalul virtual de comunicație asociat. Canalul virtual de comunicație este constituit din două streamuri – unul de intrare și altul de ieșire. Metodele getInputStream() și getOutputStream() întorc referințele la aceste streamuri.

Operația de închidere a comunicației se face prin apelul metodei close (). La închidere se poate asigura transmisia mesajelor care mai sunt pe drum, precum și eliberarea resurselor folosite de soclu. Dacă nu este realizată explicit, operația de închidere a soclului este făcută automat, de către sistemul de operare. Se recomandă închiderea soclurilor de către programator în momentul în care nu mai sunt necesare pentru comunicație, deoarece închiderea implicită realizată de sistem se face numai la colectarea memoriei disponibile.

Serverul este programul care ascultă cererile venite de la clienți și le oferă serviciul pentru care a fost creat. Identificarea serverelor se face prin intermediul portului pe care serverul așteaptă cererile de conexiune venite din partea clienților. Majoritatea serviciilor foarte des folosite în Internet au asociate porturi standardizate, pentru a permite clienților să opereze cu diferite servere în vederea obținerii unui serviciu.

Primul lucru pe care trebui să-l facă un program server este să se asocieze portului stabilit la momentul proiectării aplicației și să inițieze ascultarea cererilor de servicii venite de la clienți. Aceste lucruri se realizează prin constructorul clasei ServerSocket, clasa care implementează soclul programului server.

Un lucru esențial în proiectarea unei aplicații server este faptul că aceasta trebuie construită în așa fel încât să poată prelucra în paralel cererile clienților. Acest lucru se realizează prin folosirea mai multor fire de execuție, fiecare fir de execuție ocupându-se cu un singur client. De asemenea este prevăzut un mecanism pentru a limita numărul de cereri care pot fi prelucrate în paralel și deci și numărul firelor de execuție care rulează la un moment dat. Implicit acest număr este 50, dar poate fi specificat ca argument al constructorului. Orice cerere nouă va fi respinsă dacă numărul de cereri prelucrate are valoarea maximă specificată.

Acțiunile de creare a unui canal de comunicație virtual pot fi grupate în două categorii:

1. Acțiuni executate de aplicația client:

creează un soclu

legarea sa la un anumit port TCP și adresa IP a calculatorului client

se conectează la server

transmite /primește date prin soclu

închide soclul-conexiune.

2. Acțiuni executate de aplicația server:

creează un soclu – server

leagă soclul la adresa IP și portul sau

așteptă un apel de la client

după conectarea clientului, serverul acceptă conectarea creând un nou soclu pentru servirea clientului

Soclul server revine la așteptarea unei alte conectări

Soclul nou creat execută operațiile de primire /trimitere a datelor cu clientul după care se închide.

Capitolul 4

Proiectarea și programarea în Java a Aplicație denumită

Schimb de cărți.

4.1 Obiective

Aplicația proiectată are drept scop reducerea banilor cheltuiți de studenți pentru achiziționarea cărților necesare de a lungul anilor de facultate și nu numai. Studenții putând să își vândă cărțile deținute sau sa le schimbe cu altele pe care le doresc. Utilizatorul creând o cerere sau ofertând o carte din baza de date. Luând contact cu deținătorul acesteia prin e-mail și urmând să se înțeleagă pentru tranzacția ce doresc să o facă.

4.2 Structura magazinului și baza de date

Structural, aplicația este compusă din 2 secțiuni:

Secțiunea de prezentare;

Secțiunea de client;

4.2.1. Secțiunea de prezentare se adresează vizitatorului obișnuit, neînregistrat, care poate afla informații despre aplicație, poate avea acces la secțiunea Caută Carți și poate afla mai multe detalii despre cărțile care reprezintă un interes, completând un formular cu anumite filtre pentru realizarea căutării. magazin sau un anume produs prin completarea unui formular. Răspunsul va fi trimis prin e-mail utilizatorului. Principalele pagini care sunt accesibile acestui tip de utilizator (guest) sunt: index.scala.html, main.scala.html, register.scala.html și search.scala.html. Pentru a putea crea o cerere sau sa oferteze o carte, un oaspete al magazinului virtual va trebui să se înregistreze, folosind pagina register.scala.html.

4.2.2. Secțiunea de client este disponibilă utilizatorilor înregistrați. Aceștia au posibilitatea, pe lângă facilitățile obișnuite oferite unui oaspete, să creeze cereri și să oferte pentru cărțile dorite de aceștia.. Paginile principale aflate la dispoziția unui client sunt myoffers.scala.html și add.scala.html, unde clienții pot adăuga în baza de date cărțile pe care doresc să le vândă. Odată ce au găsit un produs ce doresc să îl achiziționeze acesta poate lua legătura cu vânzătorul utilizând butonul de contact prin care îi va trimite un e-mail, urmând să aștepte răspuns.

4.2.3. Baza de date folosită este cea aparținând serverului MySQL (PostgreeSQL) și conține 4 tabele: book, offer, request, student.

Tabela book este de tip MyISAM și are următoarele câmpuri:

Primary-key – cheia primară al tabelei;

authors – numele complet al autorilor cărții;

edition – reprezintă numărul ediției;

isbn – isbn-ul cărții respective care este unic;

name – numele cărții;

price – prețul cerut de cel care a adăugat cartea în baza de date;

publisher– editura cărții;

Tabela offer este de tip MyISAM și are următoarele câmpuri:

primary-key – cheia primară al tabelei;

book-primary-key – cheia primară a cărții;

condition – reprezintă felul cum este produsul nou/folosit;

offer_id – id-ul ofertei;

price – prețul la care se vinde cartea;

quantity– numărul de cărți vândute;

student_primary_key – cheia primară a studentului;

Tabela request este de tip MyISAM și are următoarele câmpuri:

Similar Posts

  • Fiabilitatea In Arhitectura Calculatoarelor

    Introducere Principalul subiect al teoriei fiabilității (reliability theory) este construirea sistemelor fiabile din componente nefiabile. Dacă un sistem ar funcționa numai atunci toate componentele sale ar fi funcționale, ar fi virtual imposibil de construit un sistem complex, pentru că fiabilitatea ar descrește exponențial cu numărul de componente. Principala unealtă folosită în construirea sistemelor complexe este…

  • Circuite Secventiale (rtl) Pipeline

    Circuite Secventiale (RTL) Pipeline Scopul lucrarii: Analizaprincipiului de functionare a metodei de conveerizare a datelorsieficientasa Sarcinalucrarii: De descris in ModelSim circuitul logic a modulului de inmultire 4×4 si a modulului 4×4 cu registri intermediari. Considerente teoretice: Circuitele de deplasare ne permit realizarea multiplicării numai cu puterile întregi ale lui 2. Pentru a realiza orice înmulțire…

  • Aplicatie Informatica Pentru Gestiunea Automata a Pieselor Si Accesoriilor Pentru Automobile

    LUCRARE DE LICENȚĂ Aplicație informatică pentru gestiunea automată a pieselor și accesoriilor pentru automobile Cuprins: Introducere În ultimii ani, cel mai importante aspecte în domeniul tehnologiei informației este reprezentat de dezvoltarea bazelor de date, acestea având un impact decisiv asupra modului de organizare și funcționare a numeroaselor instituții și servicii, printre care și SC ELY-AUTO…

  • Realizarea Unei Pagini Web Pentru Agentia Cronos

    Introducere Cap.1 Studiul , analiza și prezentarea sistemului existent 1.1. Istoria firmei si Locul in sfera economica 1.2.1 Obiectivul de activitate al firmei 1.2.2 Studiul sistemului de conducere 1.2.3 Studiul sistemului condus 1.3 Studiul sistemului informațional 1.3.1 Fluxul de documente aferent temei 1.3.2 Analiza sistemului informatic existent 1.3.3 Modelarea datelor și prelucrărilor Cap.2 Proiectarea de…

  • Implementarea Unei Infrastructuri Microsoft Exchange Server 2010

    CUPRINS 1. INTRODUCERE…………………………………………………………………………………….3 1.1 Context…………………………………………………………………………………………………………….3 1.2 Tema proiectului………………………………………………………………………………………………..5 2. FUNDAMENTAREA TEORETICĂ……………………………………………………….6 2.1 Sistemul de operare Windows Server 2008 R2………………………………………………………6 2.1.1 Prezentare generală……………………………………………………………………………….6 2.1.2 Versiunile sistemului de operare Windows Server 2008……………………………7 2.2 Active Directory………………………………………………………………………………………………10 2.2.1 Introducere în Active Directory……………………………………………………………10 2.2.2 Rezolvare de nume……………………………………………………………………………..11 2.2.3 Infrastructura Active Directory…………………………………………………………….13 2.2.4 Accesul la resurse……………………………………………………………………………….15 2.3 Microsoft Exchange 2010…………………………………………………………………………………18 2.3.1…