. Studiu Comparativ al Suportului Soft Oferit de Diferite Medii de Programare Pentru Programarea Distri

STUDIU

COMPARATIV AL SUPORTULUI SOFT OFERIT DE DIFERITE MEDII DE PROGRAMARE PENTRU PROGRAMAREA DISTRIBUITĂ FOLOSIND SOCKET

Subiectul lucrării

Lucrarea tratează în special conceptul de socket utilizat în programarea distribuită dar și câteva aspecte privind lucrul cu baze de date în Java, C# și Delphi.

Structura lucrării

Capitolul 1 „PREZENTAREA SUPORTULUI OFERIT DE JAVA, C# ȘI DELPHI PENTRU DEZVOLTAREA APLICAȚIILOR” prezintă caracteristicile limbajelor și mediilor de programare Java, C# și Delphi referitoare la dezvoltarea aplicațiilor.

Capitolului 2 „PROGRAMARE DISTRIBUITĂ FOLOSIND SOCKET” are rolul de a prezenta aspecte generale ale programării cu socket. Sunt prezentate în acest capitol câteva analogii între comunicarea prin socket și tipurile de comunicație existente în viața cotidiană, tipuri de socket, repere pentru alegerea tipului de socket și scenariul aplicațiilor socket.

Capitolul 3 „PREZENTARE COMPARATIVĂ A SUPORTURILOR SOFT OFERITE DE JAVA ȘI C# PENTRU PROGRAMAREA CU SOCKET” prezintă un studiu comparativ între suportul soft oferit de Java și C# pentru programarea cu socket.

Capitolul 4 „SUPORTUL SOFT OFERIT DE MEDIUL DELPHI PENTRU PROGRAMAREA CU SOCKET” prezintă suportul oferit de Delphi pentru programarea cu socket. Delphi pune la dispoziția programatorilor două componente (TserverSocket și TClientSocket) care oferă suport aplicației pentru realizarea conexiunilor cu alte gazde din rețeaua respectivă și pentru scrierea și citirea informațiilor peste acea conexiune.

Capitolul 5 „ADMINISTRAREA BAZELOR DE DATE CU DIFERITE MEDII DE PROGRAMARE” prezintă mecanisme de conectarea la o bază de date și mecanisme de accesare a datelor pentru cele trei limbaje de programare. O bază de date relațională este locul ideal de stocare a volumelor mari de date accesibile pentru mulți utilizatori. Navigând în World Wilde Web, un lucru este evident: există aici o mare cantitate de informații. Multe companii utilizează baze de date relaționale pentru a gestiona datele din propriile lor situri Web. Pentru intranet se poate utilza, de exemplu, o bază de date relațională ca „back end” pentru crearea aplicațiilor mai sofisticate.

Capitolul 6 „APLICAȚIE DISTRIBUITĂ – DICȚIONAR ELECTRONIC” prezintă o aplicație distribuită implementată în limbajele Java, C# și Delphi pentru a sublinia asemănările și deosebirile între suportul soft oferit de diferite medii de programare pentru programarea cu socket.

Originalitatea lucrării

Aplicația folosește mecanisme de conectare la o bază de date, mecanisme de acces a datelor dintr-o bază de date și valorifică suportul soft pentru programarea cu socket oferit de clele trei limbaje de programare.

În sprijinul clasificării înțelesului cuvintelor am folosit formule care menționează cuvintele cu care cuvântul titlu explicat apare cel mai des legat în vorbire, într-o îmbinare liberă. În termeni de specialitate, acest fel de a cita s-ar putea numi „indicare a unor contexte specifice și/sau uzuale”. Un asemenea context specific poate da cuvântului un sens în oarecare masură diferit de cel cu care cuvântul apare în alte îmbinari libere ale aceluiași sens. Dicționarul electronic (în cazul nostru român-englez) cuprinde cuvintele unei limbi explicate în acceași limbă și apoi traduse într-o altă limbă

Aplicațiile dezvoltate cu C# și Java, sunt aplicații cu server concurent astfel încât pentru fiecare cerere de conectare acceptată de server se lansează un fir de execuție care se ocupă de comunicarea dintre client și server. Server-ul este multifir pentru a putea procesa mai multe conexiuni client-server simultan.

În Delphi, socket-urile de server asociază o coadă la canalele lor de comunicare, unde înregistrează cererile clienților. Dacă socket-ul server acceptă unui client cererea de conexiune, se va forma un nou socket pentru conectarea clientului, pentru ca acel canal de comunicare, deschis de server, să poată rămâne în așteptarea altor cereri de la alți clienți.

Server-ul ține evidența clienților conectați, a cererilor solicitate și a serviciilor oferite clienților la un moment dat.

Partea client a aplicației permite ulilizatorilor să solicite conecatrea la server. Dacă cererea de conectare este acceptată de server, atunci clientul poate solicita cereri de formule de traducere.

PREZENTAREA SUPORTULUI OFERIT DE JAVA, C# ȘI DELPHI PENTRU DEZVOLTAREA APLICAȚIILOR

Prezentarea limbajului de programare JAVA

Introducere

Java este un limbaj de programare orientat pe obiecte, proiectat pentru a fi portabil pe mai multe platforme și sisteme de operare. Dezvoltat de Sun Microsystems, Java este modelat după limbajul de programare C++ și include carecteristici speciale care îl fac ideal pentru programele pe Internet.

În anii ’60, C++ a constituit fundamentul pentru un nou pas înainte în programare. Limbajul Java depășește multe din limitările limbajelor C și C++. Este un limbaj portabil aceasta însemnând că programele scrise în Java pot fi rulate pe mai multe tipuri de calculatoare. Programele scrise în Java pot fi atașate paginilor Web și executate pe calculatoarele utilizatorilor în momentul în care se încarcă pagina. În general nu contează ce fel de calculator sau program de navigare pe Internet execută peogramul Java. Ar trebui să meargă bine pentru orice program de navigare pe Internet. Aceasta este teoria deși nu se întâmplă întotdeauna așa în practică.

Cei familiarizați cu limbajele C/C++ vor descoperi că Java este un limbaj ușor de stăpânit și încorporează principiile de bază ale programării orientate pe obiect, deși elimină unele din construcțiile mai complicate, cum ar fi moștenirea multiplă și șabloanele.

Dezvoltarea aplicațiilor utilizând Java

Kitul de dezvoltare Java (JDK-Java Developer’s Kit) este o colecție de software de la firma Sun care cuprinde tot ce este nevoie pentru dezvoltarea plicațiilor Java.

Cu Java se pot crea două tipuri de programe: un applet sau o aplicație. Appletrurile sunt programe speciale în Java care sunt executate în cadrul unui browser Web. O aplicație Java este un program independent de browser și poate rula ca un program de sine stătător. Appleturile java nu sunt cu mult mai diferite de aplicațiile autonome în Java. Se poate să se înceapă dezvoltarea programelor cu un applet sau cu o aplicație, trcerea de la una la alta facându-se foarte ușor. Pentru că un applet este rulat din cadrul unui browser Web, el are avantajul unei ferestre existente și capacitatea de a răspunde evenimentelor de interfață cu utilizatorul prevăzute de browser. În plus, deoarece appleturile sunt proiectate pentru utilizarea în rețea, Java este mult mai restrictiv cu tipurile de acces pe care appleturile le pot avea la sistemul de fișiere decât cu aplicațiile non-rețea.

Sun a proiectat de la început limbajul Java pentru Internet. Un Intranet este o versiune de uz intern a Internetului. Un intranet utilizează acceași tehnologie, aceleași software și același echipament cu Internetul (în principal TCP/IP). Diferența între ele este că Internetul deține servere de informații aflate la distanțe foarte mari, controlate de alte organizații, iar în cadrul Intranetului serverele și calculatoarele client sunt controlate de firma care le administrează. În ultimii ani Intranetul a cunoscut o popularitate foarte mare pentru că oferă la un cost foarte mic o modalitate de întreținere și distribuire a informațiilor interne ale unei firme, intr-o formă ușor de utilizat.

Deoarece intranetul lucrează la fel ca Internetul, Java își găsește în acest caz un loc în intranetul firmelor. Toate tehnicile de lucru care se utilizează pentru aplicațiile Internet pot fi utilizate și aplicate și în intranet. Cu Java se pot crea aplicații care să ofere interfețe prietenoase pentru bazele de date, stocarea documentelor, controlul echipamentelor și așa mai departe, care să ruleze pe orice calculator, de la Macintosh la PC sau la stațiile de lucru UNIX.

Atunci când spunem despre un cod că este robust facem referire la fiabilitatea sa. Deși Java nu a eliminat codul nesigur, a reușit să facă mai accesibilă scrierea unui cod de înaltă calitate. Java elimină problemele de memorie care sunt obișnuite în limbaje cum ar fi C și C++. Java nu aceptă accesul direct la pointeri de memorie. De asemenea, Java efectuează verificări în timpul rulării programului pentru a se asigura că toate referirile la tablouri și șiruri de caractere se află între limitele fiecărui element. În alte limbaje de programare, multe dintre erorile logice apar din cauză că programele nu eliberează memoria pe care ar trebui să o elibereze sau eliberează aceeași memorie de mai mlte ori. Java efectuează o „curățenie” automată care eliberează memoria neutilizată, evitând necesitatea ca programul să elibereze memoria neutilizată.

JDK conține compilatorul Java, depanatorul și un vizualizator de appleturi cu ajutorul căruia appleturile pot rula în afara unui browser, precum și documentație și exemple de aplicații.

Convenția de denumire a fișierelor Java

Convenția de denumire a fișierelor Java este următoarea: fiecare fișier cu cod sursă Java trebuie să aibe extensia .java. În plus, fiecare nume de fișier trebuie să corespundă numelui clasei publice definite în fișier. Numele fișierului cu codul sursă trebuie să corespundă exact numelui clasei, inclusiv în ce privește majusculele și literele mici. Fișierul obiect creat de compilatorul Java va avea extensia .class. Acest fișier este cel pe care serverul Web îl descarcă în browser, iar browserul la rândul său interpretează și execută conținutul fișierului.

Prezentarea mediului de progarmare petru C#

Introducere

În prezent, C și C++ sunt cele mai folosite limbaje pentru dezvoltarea aplicațiilor comerciale și de afaceri. Datorită complexității relativ mari asociate acestor limbaje, de multe ori s-a dorit un limbaj care să ofere un echilibru mai bun între putere și productivitate. Soluția Microsoft la această problemă este C#.

Microsoft declară că: „C# este simplu, modern, orientat pe obiecte și un limbaj de programare solid, derivat din C și C++”. Orientat pe obiecte, din proiectare, C# oferă acces la clasele de biblioteci disponibile programatorilor în Visual Basic și Visual C++. Cu toate acestea, C# nu oferă suport pentru propria sa clasă de biblioteci.

Dezvoltarea aplicațiilor cu limbajul C#

C# este unul dintre cele patru limbaje Microsoft care ne duc inițial la .NET, împreună cu C++, Visual Basic și Jscript. Aplicațiile variază de la console de sine stătătoare, de tipul aplicații executate în linia de comandă sau aplicații rulate în modul DOS, până la programe pentru Windows și proiectare de pagini Web.

În loc să folosim Visual Basic pentru dezvoltarea rapidă a interfețelor, C++ pentru o programare puternică și J++ sau Java pentru activarea funcțiilor Web intr-o aplicație, putem folosi acum un limbaj de programare cuprinzător care le face pe toate, C#. Soluția unei probleme poate include componente din C++, C# și Visual Basic, toate integrate într-un singur executabil.

La Runtime, toate limbajele folosesc în comun un set mare de resurse:

Modelul programării orientate pe obiecte (moștenire, polimorfism, manipularea excepțiilor, colectarea deșeurilor);

Modelul de protecție;

Sistemul de tastare („type system”- toate limbajele care fac parte din pachetul .NET trebuie să aibe un set comun de concepte pentru a putea fiintegrate. Orice limbaj trebuie să recunoască și să poată manipula niște tipuri comune);

Toate clasele de bază din .NET;

Multe din clasele de tip Framework din .NET;

Dezvoltarea, depanarea și instrumentele de proiectare;

Execuția și managementul codului;

IL (IL– Intermediar Language) native pentru translatoare (deși există mai multe limbaje de programare, la compilare acestea vor produce cod în același limbaj intermediar, IL).

C# este o alegere bună pentru dezvoltarea unei game variate de componente, de la obiecte de afaceri de nivel înalt până la aplicații la nivel de sistem. Folosind construcția simplă a limbastem. Folosind construcția simplă a limbajului C#, progamatorii pot dezvolta rapid aplicații (RAD – Rapid Application Developement) fără să „sacrifice” puterea și controlul asociate cu C și C++. RAD înseamnă mai mult decât realizarea prototipului de interfața a programului. Instrumentele RAD oferă suport pentru sarcinile uzuale de programare cum ar fi accesarea fișierelor și directoarelor, accesarea rețelelor și conectivitatea cu baze de date.

Limbajul este proiectat să ajute programatorii să realizeze mai mult cu mai puține linii de cod și cu mai puține șanse de eroare. Experiența lumii reale a demonstrat că unele aplicații solicită folosirea codului nativ pentru un mediu de scriere sigur, din motive de performanță sau pentru interoperabilitatea cu interfețele de programare a aplicației. C# rezolvă această problemă prin următoarele caracteristici:

oferă suport nativ pentru COM (Component Object Model) și API-uri (Application Program Interfaces) pentru Windows;

oferă suport pentru folosirea limitată a pointerilor nativi- în interiorul unui bloc de cod marcat special este permis managementul manual al memoriei și aritmetica pointerilor;

implementează fiecare obiect ca obiect COM.

C# ca și Java poate fi extins cu ușurință pentru dezvoltarea aplicațiilor pentru pagini Web. Prin .NET Framework, scrierea aplicațiilor Web folosind Web Forms este foarte asemănătoare cu scrierea de programe folosind Windows Forms.

Cerințe software și hardware

Pentru a programa în C# este nevoie de: Visual Studio .NET și un calculator pe care ruleză Windows 2000. Visual Studio .NET nu funcționează (din păcate) pe nici o versiune de Windows anterioară versiunii 2000.

Prezentarea mediului Visual Studio .NET

După crearea sau deschiderea unui proiect, Visual Studio .NET deschide fereastra mediului integrat de dezvoltare (IDE). Visual Studio .NET împarte fereastra IDE în mai multe panouri. Fiecare panou conține unul sau mai multe grupuri de ferestre. Grupurile de ferestre oferă programatorilor posibilitatea de a interacționa cu codul sursă sau cu diversele utilitare ale IDE.

În afară de compilator și editorul de legături, Visual Studio oferă un editor, un depanator de programe integrat, utilitarul Solution Explorer pentru administrarea proiectelor și un sistem extins de help.

Panoul din stânga al ferestrei Visual Studio prezintă o zonă de lucru care se numește paleta de design. Acesta oferă posibilitatea de a crea aplicații Windows prin tragerea și plasarea componentelor pe suprafața paletei. Componentele se găsesc în biblioteca Windows Forms, inclusă în Visual Studio.

Panoul din stânga este un grup de ferestre. Fiecare fișier sursă care este încărcat într-o fereastră de editare are panoul lui cu etichete de selecție. Fiecare astfel de fișier poate fi vizualizat acționând cu mouse-ul pe eticheta corespunzătoare.

Panoul din dreapta sus indică soluția și proiectul curent. Acest panou se numește Solution Exporer. Acționând etichetele din partea de jos a acestui panou vom obține o vedere a claselor. Class View prezintă toate clasele ce pac parte din proiect.

În panoul din dreapta jos se găsesc ferestrele Dynamic Help și Properties. În timpul dezvoltării programelor, Dynamic Help afișează o lista help, ordonată pe subiecte. Lista se schimbă în funcție de ceea ce se lucrează. Fereastra Properties poate fi utilizată pentru a vizualiza interactiv și a seta proprietățile unui control. Setarea valorilor implicite ale unei proprietăți este o activitate ce se desfășoară în timpul proiectării (design time).

Prezentarea mediului de programare DELPHI

Introducere

Delphi este un mediu de programare, vizual, orientat obiect, pentru dezvoltarea rapidă a aplicațiilor (Rapid Application Developement). Acesta pune la dispoziție o interfață cu multe trăsături automatizate, pentru a facilita dezvoltarea aplicațiilor.

Limbajul folosit de Delphi este Object Pascal, care este o dezvoltare a limbajului „clasic” Pascal. Sistemul este prevăzut cu un meniu Help foarte bine documentat, care include în afara comenzilor standard și comenzi pentru prezentarea limbajului Object Pascal.

Sistemul Delphi creează direct fișiere executabile, care pot fi lansate în execuție chiar și în cazul în care, în calculatorul respectiv nu este instalat sistemul Delphi.

Delphi permite configurarea mediului de lucru, prin adăugarea de instrumente de lucru personalizate folosind Open Tools API (Application Programming Interface). Asfel poate fi utilizat un instrument de lucru preferat în locul celor furnizate de mediul IDE (Integrated Development Environment).

Delphi este un limbaj orientat pe obiecte deoarece îmbină cele trei concepte fundamentale care stau la baza programării orientate spre obiecte și anume: încapsularea (permite combinarea datelor și a codului pentru definirea claselor), moștenirea (cu ajutorul unor clase se pot defini alte clase) și polimorfismul (tratrea unei clase descendente în relație cu o clasă parinte). Delphi admite toate instrumentele standard de reutilizare a codului, cum ar fi bibliotecile DLL și fișierele OBJ.

Dezvoltarea aplicațiilor cu Delphi

Delphi oferă suport complet pentru aplicațiile Windows 95 și Windows NT. Delphi face posibil accesul la interfața API prin intermediul bibliotecii VCL. Pe lângă multe alte condiții pe care trebuie să le îndeplinească o aplicație se numără și robustețea. Orice aplicație este robustă dacă în urma apariției unor mesaje de eroare nu se blocheză și nu pierde din date. Delphi pune la dispoziția utilizatorului mecanisme prin care se evită oprirea aplicațiilor.

Mediul Delphi oferă următoarele facilități pentru dezvoltarea aplicațiilor: paleta de componente (conține componentele ce pot fi utilizate în dezvoltarea aplicațiilor, organizate în pagini de componente), bara de acces rapid (speed bar) și inspectorul de obiecte (Object Inspector).

Prezentarea barei de acces

Bara de acces rapid are două secțiuni: secțiunea din partea stângă, care cuprinde butoanele de acces rapid care au diferite sarcini cum ar fi deschiderea, salvarea, compilarea, proiectului, rularea lui, și secțiunea din partea dreaptă contine un set complet de componente ce fac parte din biblioteca de componente vizuale (VCL Visual Component Library).

Cu ajutorul diferitelor metode cu care sunt prevăzute componentele, acestea pot fi modificate din punct de vedere al comportamentului în momentul în care este declanșat un anumit eveniment (de exemplu efectuarea unui clic de mouse pe componenta respectivă). O componentă specială este forma. Formele pot „reacționa ” la 21 de evenimente, iar pentru descrierea lor pot fi utilizate 38 de proprietăți, care pot fi specificate în perioada elaborării proiectului prin intermediul inspectorului de obiecte.

Inspectorul de obiecte

Inspectorul de obiecte este o fereastră formată din două pagini, care face legătura între interfața aplicației și codul scris de programator. Inspectorul de obiecte se ocupă de stabilirea proprietăților inițiale ale formelor și ale celorlalte componente, in perioada de elaborare a proiectului. Aceste proprietăți se găsesc pe pagina etichetată Properties din cadrul Object Inspector.

De asemenea, o altă sarcină ce cade sub incidența inspectorului de obiecte este și asocierea de evenimente formelor sau componentelor ce aparțin unei aplicații.

Fereastra formei

Fereastra formei ste un obiect special care este destinat pentru proiectarea ferestrei care va fi vizibilă în timpul lansării în execuție a proiectului. De fiecare dată când se lansează în execuție sistemul Delphi se creează o formă, care inițial nu conține nici o componentă. Pe formă se pot adăuga componente vizuale și nevizuale, care alcătuiesc interfața cu utilizatorul. O aplicație poate conține mai multe forme. O formă corespunde unei ferestre principale a aplicației, iar diferitelor ferestre de dialog utilizate de freastra principală le corespund alte forme.

Fereastra de editare de cod

În fereastra de editare de cod se introduce codul programului, care stabilește modul de tratare a diferitelor evenimente. Conținutul ferestrelor de editare de cod este salvat in diferite unit-ri. Extensia fișierelor de unități este întotdeauna *.pas. Fișierele care au această extensie conțin cod scris în limbajul Object Pascal, limbajul de programare utilizat de Delphi.

PROGRAMARE DISTRIBUITĂ FOLOSIND SOCKET

Prezentare generală

Rolul acestui capitol este de a prezenta interfața de programare a aplicațiilor (API – Application Programing Interface) oferită pentru lucrul cu socket. Această interfață API asigură comunicarea cu nivelul transport (TCP sau UDP) a familiei de protocoale, deoarece acest nivel este cel care pune la dispoziție comunicarea „capăt la capăt” necesară programării aplicațiilor de rețea.

Orice interfață API depinde atât de platforma pe care se rulează (sistemul de operare Windows) cât și de limbajul pentru care este destinată. O API constă dintr-o bibliotecă de funcții disponibile programatorilor.

Există o analogie între operațiile cu perifericele într-un sistem de calcul și comunicațiile în rețea ale acelui sistem. Apelurile sistem prevăzute pentru accesul la fișiere pot servi și pentru comunicarea în rețea, dar pentru a ține cont de perticularitățile rețelelor a fost introdus un concept nou, acela de „socket”.

Conceptul de socket

Un socket este un „capăt de comunicație” sau „un punct final de comunicație”, care poate fi numit și adresat într-o rețea. La fel ca și fișierele, socket-urile sunt repezentate în sistem prin descriptori, dar spre deosebire de fișiere, un socket există doar în memorie.

Se pot face analogii între comunicarea prin socket și tipurile de comunicație existente în viața cotidiană. Prima analogie aseamănă un socket cu o cutie poștală în care proprietarul ei (aplicația) depune și ridică corespondența. Factorul poștal (furnizorul mediului de transport) deschide cutia, ridică corespondența de expediat și depune corespondența sosită la adresa corespunzătoare.

A doua analogie este cu un aparat telefonic, la care proprietarul formează numă’rul de telefon și după stabilirea legăturii începe conversația cu persoana de la celălalt capăt al firului.

Aparatul telefonic legat la rețeaua de telecomunicații, asigură stabilitatea legăturii, până la închiderea unuia dintre cele două aparate telefonice.

Două aplicații pot comunica între ele prin socket doar după ce sistemul a alocat fiecăreia un socket. Există un număr de descriptori de socket rezervați pentru aplicațiile de sistem, restul descriptorilor fiind disponibili utilizatorilor.

Tipuri de socket

Din punct de vedere al transportului de date există două tipuri de socket: socket stream și socket datagram. Comunicarea este posibilă numai dacă la ambele capete este utilizat același tip de socket.

O comunicare în rețea poate fi cu conexiune sau fără conexiune.

Socket stream

În cazul comunicării cu conexiune datele sunt transmise fară erori și fără duplicări, după ce s-a stabilit în prealabil o conexiune între cele două puncte ale comunicației. Un lucru foarte important este că nu este impusă o limitare asupra datelor, acestea fiind considerate șiruri de octeți. Suportul necesar pentru comunicarea cu conexiune este oferit de interfața socket stream, iar transportul datelor este realizat folosind protocolul TCP. Pentru acest tip de comunicare este potrivită analogia cu aparatul telefonic descrisă în secțiunea precedentă.

Socket datagram

Pentru aplicațiile fără conexiune, nu avem nici un fel de garanție privind recepționarea datelor. Serviciile fără conexiune pentru transmiterea datelor sunt asigurate de interfața socket datagram. In cazul acestui tip de comunicație datele pot fi pierdute, duplicate sau pot ajunge la destinatar în altă ordine decât cea în care au fost transmise. Față de comunicarea cu conexiune, marimea cadrelor de date transmise este limitată de numărul de octeți care pot fi transmiși într-o singură tranzacție.

Pentru comunicarea fără conexiune transportul datelor este realizat pe baza protocolului UDP. În acest caz este potrivită analogia cu cutia poștală făcută în secțiunea precedentă.

Repere pentru alegerea tipului de socket

În vederea alegerii unui anumit tip de socket pentru realizarea aplicațiilor trebuie avute în vedere mai multe aspecte.

Primul aspect este cel amintit în secțiunea anterioară: realizarea comunicației unei aplicații cu o altă aplicație impune folosirea de către ambii parteneri a aceluiași protocol – TCP dacă se dorește comunicarea orientată pe conexiune, respectiv UDP pentru comunicarea fără conexiune.

Un alt aspect care trebuie luat în calcul este siguranța transmiterii datelor. Protoculul TCP asigură transmiterea cadrelor de date fără eroare, fără duplicate și în ordinea în care acestea au fost transmise. Există două cauze principale de apariție a unor erori: coruperea datelor și pierderea datelor.

Datorită lucrului cu comutare de pachete este posibil ca două pachete consecutive să străbată mediul de comunicație pe rute diferite de la expeditor la destinatar și astfel pachetul care a plecat ultimul să ajungă primul.

Pentru a evita aceste probleme, protocolul TCP furnizează un set de servicii pentru controlul fluxului, precum și pentru fiabilitatea comunicării. TCP permite transmisia datelor în ambele sensuri (full-duplex).

În cazul in care aplicația implementează un mod propriu de control al datelor sau nu este necesară o transmisie sigură a datelor, preferându-se o viteză mai mare în ceea ce privește transmiterea datelor, atunci este recomandată folosirea socket-urilor de tip datagram. Câștigul pe care îl oferă folosirea socket datagram este viteza de transmisie a datelor.

Transportul datelor este realizat pe baza protocolului UDP – protocol fără conexiune, care nu garanteză că datagramele ajung la destinație.

Folosirea socket-urilor datagram este recomandată pentru aplicațiile mai simple, unde lipsa fiabilității datelor nu constituie un impediment.

Dacă comunicația se desfășoară într-o rețea LAN (Local Area Network), atunci în majoritatea cazurilor este recomandată folosirea tipului socket datagram, iar pentru rețelele WAN (Wide Area Network) este recomandată folosirea tipului socket stream.

Scenariul aplicațiilor socket

Arhitectura generală pentru comunicația cu socket este prezentată în figura de mai jos:

Rețelele oferă posibilitatea de a crea noi tipuri de aplicații, deoarece nu mai este necesar ca un singur calculator să execute totul. În cadrul unei rețele, câteve calculatoare, numite servere, efectuează acțivități specializate în folosul altor programe. Un program care utilizează un server se numește client. Serverul este un program software care, care rulează în mod continuu pe un calculator, cu scopul de a furniza servicii altor programe. Relația client-server, tipică aplicațiilor de rețea, este asimetrică, deci un program trebuie să cunoască ce rol joacă. Pentru a scrie aplicații client-server, trebuie create două programe, care trebuie să respecte un set de reguli pentru a comunica. Aceste reguli se numesc protocoale. Protocoalele definesc modul de interacțiune dintre client și server.

Modelul client-server este cel mai popular model pentru implementarea aplicațiilor distribuite. În acest model cel care oferă servicii clienților este serverul, iar clienții sunt cei care solicită serviciile. De regulă serverele sunt proiectate astfel încât cererile să fie acceptate numai într-o formă standard.

În modelul client-server programul cu rol de server trebuie pornit primul, iar proiectarea și codificarea sa se fac după următoarea schemă:

Se deschide un canal de comunicare și se informează calculatorul local că programul este pregătit să accepte cereri de la clienți la o locație (adresă) determinată.

Programul rămâne în așteptare până la sosirea unei cereri de la un client.

Programul acceptă cererea și o tratează, elaborând și un mesaj de răspuns care se trimite clientului.

Se revine la pasul 2.

Dacă severul este operațional, se pot proiecta aplicațiile client cu condiția ca să respecte forma de cerere acceptată de server. Pentru programele client acțiunule tipice sunt următoarele:

Deschiderea unui canal de comunicare la o locație determinată a unui anumit calculator

Emiterea de cereri de servicii către server și recepționarea rezultatelor ori de câte ori este necesar.

Închiderea canalului de comunicare și terminarea programului.

Serverele deschid canale de comunicare în mod pasiv, iar programele client sunt elelmente active în aplicațiile de tip client-server.

Scenariul pentru aplicațiile bazate pe protocoale cu conexiune

Pentru a scrie aplicații bazate pe protocolul cu servicii orientate pe conexiune, se folosesc câteva apeluri sistem, dintre care unele sunt apelate de server iar altele de client. Scenariul tipic pentru transferurile cu conexiune este prezentat în figura de mai jos. Se observă că mai întâi este pornit serverul, iar clientul este lansat mai târziu, astfel încât să existe siguranța că poate găsi disponibile serviciile pe care le solicită de la server.

Scenariul pentru aplicațiile bazate pe protocoale fără conexiune

Pentru aplicațiile fără conexiune, setul de apeluri sistem este prezentat în figura de mai jos. Clientul nu trebuie să stabilească o conexiune cu serverul, ci trimite direct datagrame cu apelul sistem sendto().

Serverul nu acceptă conexiuni, ci emite un apel sistem recvfrom() și așteaptă până la sosirea unei datagrame.

În datagramă este conținută adresa de rețea a procesului client, astfel că serverul cunoaște cine a formulat cererea și unde să trimită răspunsul.

Apeluri sistem fundamentale

Apelul sistem socket()

Crearea unui socket se realizează cu apelul sistem socket(). Pentru a putea realiza comunicarea în rețea, orice program trebuie mai întâi să-și realizeze cel puțin un socket cu caracteristicile cerute de tipul de comunicare dorit.

Valoarea returnată de acest apel sistem este un descriptor de socket care este utilizat în mod asemănător cu descriptorul de fișier.

Apelul sistem bind()

Prin acest apel sistem se realizează legătura între un socket anterior creat și un punct final de comunicare. Se pot pune în evidență trei utilizări principale ale lui bind():

Serverele își înregistreză în sistem o adresă binecunoscută. Operația este necesară pentru serverele cu conexiune dar și pentru cele fără conexiune, înainte de a putea accepta cereri.

Un client își poate înregistra o adresă specifică.

Un client fără conexiune trebuie să se asigure că sistemul îi atribuie o adresă unică prin care se identifică astfel încât serverul să primească o adresă validă la care să trimită răspunsul.

În urma unui apel bind() se completează elementele adresa locală și numarul de port, care împreună definesc un punct unic de comunicație.

Apelul sistem connect()

Stabilirea unei legături între un client și un server este solicitată prin apelul sistem connect(). Rezultatul acestui apel, în cazul unui protocol cu conexiune este stabilirea efectivă a unei conexiuni între sistemul pe care rulează aplicația client și sistemul pe care rulează aplicația server. Execuția apelului implică schimbul unor mesaje între cele două sisteme pentru stabilirea parametrilor legăturii. Revenirea din apel se face numai după stabilirea cu succes a legăturii sau atunci când se detectează o eroare (raportată prin valoarea returnată).

Apelul sistem listen()

Apelul listen() este utilizat de serverele cu conexiune pentru a indica că sunt pregătite să accepte conexiuni. Prin acest apel se precizează câte apeluri connect() pot fi acceptate în timp ce serverul așteaptă terminarea unui apel accept() început. Pentru acceptarea unei cereri, serverul consumă un anumit timp pentru a efectua operațiile necesare unei cereri, chiar dacă pentru tratarea cererilor serverul creează un nou proces. În acest interval este posibil ca noi clienți să emită cereri spre același server și acestea vor fi preluate într-o coadă de așteptare. Majoritatea sistemelor de operare nu admit mai mult de cinci clienți simultan.

Apelul sistem accept()

Acceptarea unei cereri de către serverele cu conexiune se realizează prin apelul sistem accept(). Dacă nu există cereri în așteptare, serverul așteptă până la sosirea primei cereri. În cazul apariției unei erori apelul va întoarce valoarea -1, altfel va întoarce un întreg care indică un nou descriptor pe care serverul îl folosește pentru schimbul de mesaje cu clientul.

Apeluri sistem pentru transferurile efective de date

În cazul protocoalelor cu conexiune, transferurile efective de date se fac prin apelurile sistem read() și write(). Protocoalele fără conexiune sunt prevăzute cu apeluri specifice: send() și receive(), care presupun că sunt cunoscute toate elementele necesare unei conexiuni client-server (adresa IP și numărul de port) și că s-a efectuat în prealabil apelul connect(). La apelurile sendto() și recvfrom() elementele pentru identificarea calculatoarelor aflate la distanță se specifică la apel.

PREZENTARE COMPARATIVĂ A SUPORTURILOR SOFT OFERITE DE JAVA ȘI C# PENTRU PROGRAMAREA CU SOCKET

Suportul soft oferit pentru operațiile do I/O

Conceptul fundamental pentru operațiile I/O în Java este cel de stream (flux). Fluxurile se pot defini ca obiecte constând din secvențe de date care au o sursă (fluxurile de intrare) sau o destinație (fluxurile de ieșire).

Una din trăsăturile cele mai importante ale limbajului Java este că oferă o abstractizare pentru I/O în general, dar și pentru operațiile I/O în rețea.

C# oferă un set bogat de biblioteci care este transparent pentru programatori Java.

Echivalentul pachetului Java java.io este spațiul de nume System.IO din C#. Clasele din System.IO permit scrierea și citirea datelor dint-un fișier sau de la consolă. Alte pachete, precum System.Net.Socket, suportă fluxuri pentru scrierea și citirea datelor peste un canal de comunicare în rețea.

Stream-uri

Atât Java cât și C# oferă suport pentru a transmite date peste o rețea. În cele ce urmează vom urmări modul în care se realizează acest lucru.

În Java, primul pas care trebuie realizat este obținerea unui flux de ieșire OutputStream dintr-un obiect Socket, utilizând metoda getOutputStream(). Următorul pas este crearea unui obiect BufferedOutputStream cu obiectul original OutputStream în constructor. După parcurgerea acestor pași trebuie creat un obiect DataOutputStream ce are ca parametru în constructor obiectul BufferedOutputStream. După cum se observă Java utilizează trei straturi de funcționalitate ale fluxului de date.

C# folosește fluxurile, dar aici întâlnim câteva schimbări. Cea mai surprinzătoare este că atât fluxurile de intrare cât și cele de ieșire fac parte dintr-o singură clasă. De exemplu clasele BufferedInputStream și BufferedOutputStream din Java sunt combinate în C# intr-o singură clasă BufferedStream.

Conversia tipurilor de date

Datorită diferențelor arhitecturale între calculatoare și convenției de tansmitere a informațiilor multioctet în rețea, este necesară utilizarea unor metode de conversie de reprezentare a datelor. Java oferă două clase ca suport pentru convertirea datelor din reprezentarea internă în reprezentarea recunoscută în rețea: DataInputStream și DataOutputStream. C# oferă un echivalent pentru acest suport BinaryWriter și BinaryReader. Aceste două clase nu sunt clase pentru fluxuri (nu moștenesc o clasă stream), dar amândouă acceptă ca parametru în constructori un stream.

Suportul soft oferit pentru programarea cu socket

Pachetul Java.net din JDK conține clase, interfețe și excepții care implementează într-o formă orientată pe obiecte conceptele uzuale pentru comunicarea în rețea la nivel de socket: adrese Internet, URL-uri și diverse categorii de socket. Ca elemente deosedite sunt de amintit: pentru socket-uri TCP sunt prevăzute două clase distincte: Socket și ServerSocket și s-a mai introdus o clasă specială, MulticastSocket derivată din DatagramSocket pentru comunicarea multicast. Pentru comunicarea propriu-zisă, o dată ce s-a stabilit legătura între două puncte din rețea, se utilizează operațiile de introducere/extragere realizate prin intermediul fluxurilor.

C# folosește același model, dar există câteva diferențe legate de modul în care sunt implementate metodele pentru fluxurile de primire a datelor.

Pentru a putea realiza aplicații client-server trebuie utiizate în Java clasele SocketServer și Server. Java face distincție între socket-urile folosite în partea de client și socket-urile folosite în partea de server.

Crearea server-ului

Pentru crearea server-ului se folosește un obiect de tip ServerSocket care definește un număr de port. Metoda specifică acestei clase este accept(). Aceasta produce blocarea procesului apelant până la sosirea unei cereri de conectare. Obiectul ServerSocket acceptă conectarea clienților și returnează un socket prin care poate comunica cu clientul.

Se observă că metoda accept() returnează un socket client, prin care se poate desfășura comunicarea cu solicitantul de conectare acceptat.

În C# echivalentul obiectului ServerSocket este TCPListener. Clasa TCPListener face parte din spațiul de nume System.Net.Sockets. Acceptarea unei conexiuni se face utilizând metoda AcceptSocket(). Deși numele metodelor prin care este acceptată conexiunea diferă, modul de funcționalitate este același ca în Java.

Metoda AcceptSocket() așteaptă pentru o conexiune, la fel ca metoda accept() din Java. Procesul apelant este blocat până când se va returna un obiect socket. În Java, o dată obținut obiectul socket se poate apela metoda getIInputStream() sau getOutputStream() care returnează un flux de intrare respectiv de ieșire atașat socket-ului curent.

În C# primul lucru care trebuie făcut după ce s-a obținut un socket, este instanțierea clasei NetworkStream care crează un stream bazat pe protocolul TCP/IP. Constructorul clasei acceptă o instanță socket. Pentru ca server-ul să poată scrie date trbuie obținut mai întâi fluxul asociat socket-ului utilizând metoda GetStream(), iar apoi trebuie suprascrisă metoda Write() din clasa Stream pentru scrierea datelor în flux. Metoda Write() scrie o secvență de octeți în stream-ul curent și incrementează indicatorul poziției curente în strem.

O observație foarte importantă se referă la evitarea conflictelor dintre numerele de port. Fiecare aplicație rețea are nevoie de un număr unic de port. Cum utilizatorii pot rula mai multe aplicații rețea pe același calculator este important ca două aplicații să nu folosească același număr de port.

Crearea clientului

Partea de client a unei aplicații client-server conține conectarea la server, trimiterea și recepția de mesaje. Pentru a crea o aplicație client Java utilizează clasa Socket. Clasa Socket dispune de două metode pentru a permite transportul datelor în rețea: getInputStream() și getOutputStream().

Metoda getInputStream() returnează un flux de intrarea atașat socket-ului curent. Acest flux este utilizat pentru a citi informațiile de la socket.

Metoda getOutputStream() returnează un flux de ieșire atașat socket-ului curent, utilizat pentru scrierea informațiilor în socket.

Acestea sunt metodele esențiale pentru comunicarea în rețea. Constructorul Socket crează un socket și îl conecteză la calculatorul și portul specifiți ca parametri.

C# oferă mai multe posibilități de obținere a unui socket client. O posibilitate ar fi crearea unui obiect Socket, însă acesta nu este echivalentul unui obiect socket creat în Java.

Spațiul de nume System.Net.Sockets include clasa TCPClient care permite crearea unui obiect socket similar celui creat în Java utilizând clasa Socket.

Când este inițializat TCPClient, socket-ul client se conectează automat la server-ul descris de parametri. Clasa TCPClient folosește metoda GetStream() pentru a obține fluxulul atașat socket-ului.

Un alt mod de a obține un socket client este folosirea clasei Socket. Clasa Socket din C# este mai dificil de utilizat decât clasa Socket din Java, deoarece C# permite mai multă flexibilitate în alegerea tipului de conexiune. În continuare voi descrie modul în care se poate obține un socket în C# folosind clasa Socket.Primul pas pentru a obține un socket este obținerea adresei IP. Această adresă trebuie să fie un obiect IPAddress. Un astfel de obiect poate fi obținut printr-un apel al metodei Resolve() a clasei Dns. Metoda Resolve() returnează un obiect IPHostEntry. După obținerea adresei IP, trebuie creat un obiect IPEndPoint pentru a specifica socket-ului identitatea calculatorului și numărul de port la care să se conecteze.

Pentru a crea un obiect Socket trebuie precizați trei parametri. Ordinea lor este: AdressFamily, SocketType și ProtocolType. Când ServerType este Dgram, ProtocolType trebuie să fie neapărat UDP, iar când ServerType este Stream, ProtocolType trebuie să fie obligatoriu TCP. După conectarea socket-ului la server. Se poate obține fluxul NetworkStream pentru transportul datelor în rețea.

După cum se observă crearea unui socket client în C# utilizând clasa Socket, presupune un proces mai complex de creare decât dacă s-ar folosi clasa TCPClient. Avantajul oferit de clasa Socket este o mai mare flexibilitate în alegerea tipului de conexiune.

Concluzie

În C# fluxurile de intrare și de ieșire nu sunt separate în două clase așa cum se întâmplă în Java. Suportul pentru operațiile cu fluxurile de intrare și fluxurile de ieșire este oferit de acceași clasă.

Echivalentele C# pentru clasele DataInputStream și DataOutputStream din Java sunt clasele BinaryReader și BinaryWriter. Cea mai importantă metodă oferită de clasa BinaryWriter este Write() și permite scrierea datelor (aparținând tipurilor uzuale de date) în flux. Clasa BinaryReader conține metode pentru gestionarea diferitelor tipuri de date.

Un socket server creat folosind clasa TCPListener, începe să asculte canalul pentru noi conexiuni, după apelul metodei Start() și acceptă stabilirea unei conexiuni la apelul metodei AcceptSocket(). Pentru partea de client se folosește un obiect TCPClient pentru conectarea la un socket server.

SUPORTUL SOFT OFERIT DE MEDIUL DELPHI PENTRU PROGRAMAREA CU SOCKET

Introducere

Pentru a putea programa aplicații ce permit comunicarea orientată pe conexiune, Delphi pune la dispoziția programatorilor două componente (TserverSocket și TClientSocket) care oferă suport aplicației pentru realizarea conexiunilor cu alte gazde din rețeaua respectivă și pentru scrierea și citirea informațiilor peste acea conexiune.

Componentele TClientSocket și TServerSocket folosesc obiectele WindowsSockets (WinSock) pentru încapsularea apelurilor WinSock API, pentru ca în cadrul aplicației programatorul să nu fie nevoit să se ocupe cu detalii privind stabilirea conexiunii sau gestionarea mesajelor socket.

Pentru a beneficia de serviciile oferite de WinSock, trebuie să existe în dosarul \SYSTEM următoarele cinci fișiere:

WINSOCK.DLL Este o aplicație pe 16 biți care garantează compatibilitatea cu aplicațiile mai vechi (dacă este necesară o asemenea compatibilitate). De exemplu, o aplicație cum este Ping va utiliza această bibliotecă DLL.

WSOCK32.DLL Aplicațiile pe 32 de biți folosesc această bibliotecă DLL pentru a apela funcțiile WinSock API. Ea oferă suport pentru aplicațiile mai noi care folosesc socket-uri, cum ar fi aplicația TelNet.

VSOCK.VXD Windows folosește acest driver pentru a oferi suport WinSock pe 16 și pe 32 de biți pentru protocoalele IPX/SPX și TCP/IP. Acest driver furnizează suport virtual pentru fiecare mașima virtuală, făcând posibil ca Windows să efectueze mai multe operații specifice WinSock simultan. Acesta este driver-ul folosit pentru ambele protocoale.

ESTCP.VXD Driverul specific care oferă suportul necesar protocolului TCP/IP.

WSIPX.VXD Driverul specific care oferă suportul necesar protocolului IPX/SPX.

Descrierea componentelor

Pentru aplicațiile ce folosesc socket-urile, descrierea și specificarea datelor necesare realizării conexiunii precum și gestionarea mesajelor socket au loc în handlere de tratare a evenimentelor pentru componentele socket.

Componentele socket, generează evenimente în decursul deschiderii și completării unei conexiuni. Dacă aplicația trebuie să influențeze deschiderea conexiunii, sau dacă trebuie să înceapă să scrie sau să citească peste acea conexiune, trebuie scrise handlere de evnimente care răspund la aceste evenimente client, sau server.

Componenta TServerSocket

O componentă TServerSocket adăugată pe formă, transformă propria aplicația într-o aplicație TCP/IP server. Socket-urile server permit programatorului specificarea serviciilor pe care le oferă și port-ul folosit pentru deschiderea canalului de comunicare. Se poate folosi componenta socket server pentru acceptarea cererilor de conexiune din partea clienților.

Componentele TServerSocket se folosesc pentru: specificarea portului, acceptarea cererilor clienților, obținerea informațiilor despre clienții care au lansat cererea de conexiune la server și pentru închiderea conexiunilor pe care le are server-ul. Componentele socket server pot forma două tipuri de conexiuni: conexiune de ascultare (prin canalul de comunicare) și conexiuni cu aplicații client.

În urma stabilirii unei astfel de conexiuni componenta TServerSocket generează următoarele tipuri de evenimente: evenimente generate în timpul ascultării conexiunii (când se deschide canalul de comunicare) și evenimente generate în timpul conexiunilor cu aplicații client.

Evenimente generate în timpul ascultării conexiunii

Înainte de deschiderea canalului de ascultare este generat evenimentul OnListen. Se pot face schimbări asupra socket-ului folosind handler-ul de evenimente asociat lui, dar numai înaintea deschiderii canalului de comunicare.

De exemplu, dacă se dorește restricționarea adresei IP pe care server-ul o folosește pentru canalul de ascultare, acest lucru se face în handler-ul ciat evenimentului OnListen.

Evenimente generate în timpul conexiunii cu aplicația client

Când un socket server acceptă cererea de conexiune a unui client se generează următoarele evenimente:

Socket-ul server generează evenimetul OnGetSocket. Dacă se dorește crearea unui obiect personalizat TServerClientWinSocket se poate crea în handler-ul OnGetSocket.

Este generat evenimentul OnAccept. Se pot folosi proprietățile obiectului TServerClientWinSocket pentru a obține informații despre sfârșitul conexiunii aplicației client cu server-ul.

Dacă ServerType este setat stThreadBlocking, se generează evenimentul OnGetThread. Dacă se dorește personalizarea obiectului TServerClientThread se poate crea obiect nou în handler-ul de evenimente OnGetThread.

Dacă ServerType este setat stThreadBlocking, se va genera evenimentul OnThreadStart când firul de execuție își începe execuția.

Clientul încheie conexiunea și se generează evenimetul OnClientConnect. Dacă nu este activată blocarea server-ului, atunci se poate începe citirea sau scrierea prin conexiunea stabilită.

Socket-urile de server asociază o coadă la canalele lor de comunicare. În coadă se înregistrează cererile clienților, iar aceștia pot stabili conexiunea. Dacă socket-ul server acceptă unui client cererea de conexiune, se va forma un nou socket pentru conectarea clientului, pentru ca acel canal de comunicare, deschis de server, să poată rămâne în așteptarea altor cereri de la alți clienți.

Componenta TClientSocket

O componentă TClientSocket adăugată pe formă transformă propria aplicația într-o aplicație TCP/IP client. Componentele client permit specificarea server-ului cu care se dorește realizarea conexiunii și lansarea cererilor către server.

Odată deschis canalul de comunicare de către server, se poate folosi o componentă TClientSocket pentru a realiza conexiunea cu server-ul. Componentele TClientSocket se folosesc pentru: specificarea serverului cu care se dorește conexiunea, conectarea la server, obținerea informațiilor referitoare la conexiune, citirea și scrierea de la respectiv către server și închiderea conexiunii.

Evenimente generate în timpul conexiunii cu aplicația server

Când un socket client deschide o conexiune, au loc următoarele evenimente:

Un eveniment OnLookup apare înainte de realizarea conexiunii la un socket server. În acest moment nu se mai poate schimba gazda, adresa, numărul de port pentru schimbarea socket server-ului găsit.

Socket-ul Windows este setat și inițializat pentru setarea evenimentelor.

Evenimetul OnConnecting apare după ce server-ul a fost localizat. În continuare, obiectul Socket Windows disponibil prin proprietatea socket poate oferi informații despre socket-ul server aflat la celălalt punct al conexiunii. Aceasta este prima șansă pentru a se obține numărul de port și adresa IP folosită pentru conexiune, care pot diferii de numărul de port și adresa IP al canalului de ascultare al socket-ului care a acceptat conexiunea.

Cererea de conexiune este acceptată de server și completată de socket-ul client.

Un eveniment OnConnect se generează după realizarea conexiunii. Dacă socket-ul trebuie să înceapă imediat procesul de scriere sau citire peste conexiune, se scrie un handler de evenimente OnConnect care să realizeze acest lucru.

Scrierea și citirea peste conexiune

Socket-urile non-blocking generează evenimente de scriere și citire care informează socket-ul ce-l folosesc, când trebuie să scrie sau să citescă peste o conexiune. Cu socket-urile client se poate răspunde la aceste notificări în handler-ul de evenimente OnRead sau OnWrite. Socket-urile server pot răspunde la aceste evenimente în handler-ele de evenimente OnClientRead și OnClientWrite.

Obiectul windows socket asociat cu conexiunea socket-ului trebuie specificat ca parametru pentru citirea și scrierea de handler-e de evenimente. Acest obiect window socket oferă un număr de metode care permit citirea sau scrierea peste o conexiune. Pentru a citi dintr-o conexiune socket, se folosesc metodele ReceiveBuf() sau ReceiveText(). Înainte de folosirea metodei ReceiveBuf(), se folosește metoda ReceiveLength() pentru a prelua numărul estimativ de biți pe care socket-ul din cealaltă parte a conexiunii este gata să-l trimită.

Pentru scrierea peste o conexiune socket, se pot folosi una din metodele SendBuf(), SendStream() sau SendText(). Când se dorește închiderea conexiunii socket după ce s-a scris informația peste conexiune, se folosește metoda SendStreamThenDrop(). Această metodă închide conexiunea după ce s-a scris toată informația necesară. Dacă se folosesc metodele SendStream() sau SendStreamThenDrop(), nu trebuie eliberat obiectul flux. Socket-ul eliberează fluxul automat după inchiderea conexiunii. SendStreamThenDrop() închide conexiunea server cu un singur client, dar nu închide și conexiunea de ascultare.

ADMINISTRAREA BAZELOR DE DATE CU DIFERITE MEDII DE PROGRAMARE

Rolul bazelor de date relaționale în rețea

Navigând în World Wilde Web, un lucru este evident: există aici o mare cantitate de informații. Multe companii utilizează baze de date relaționale pentru a gestiona datele din propriile lor situri Web. O bază de date relațională este locul ideal de stocare a volumelor mari de date accesibile pentru mulți utilizatori. Pentru intranet se poate utilza, de exemplu, o bază de date relațională ca „back end” pentru a crearea aplicațiilor mai sofisticate.

Prezentarea conceptelor ODBC

ODBC este o interfață API pentru bazele de date relaționale, care folosește linbajul de interogare structurat (Structured Query Language -SQL) îndeplinirea unor sarcini. O aplicație care folosește ODBC se conectează la o bază de date prin intermediul unui driver scris special pentru accesul la baza de date respectivă.

ODBC este parte componentă a arhitecturii pentru servicii deschise Windows (Windows Open Services Arhitecture –WOPSA). WOPSA este modalitatea aleasă de Microsoft pentru furnizarea unui set unificat de servicii pentru sistemele de dimensiuni foarte mari. Alte servicii incluse în această arhitectură sunt interfața API pentru mesaje (MAPI) și interfața API pentru telefonie (TAPI).

ODBC poate fi utilizat penru a avea acces la orice bază de date care conține un driver ODBC. Cele mai cunoscute baze de date acceptă drivere pentru ODBC. Multe dintre aplicațiile client-server necesită folorirea unei interfețe Windows, iar producătorii de sisteme DBMS vor să câștige o mare parte din această piață, de aceea majoritatea manifestă interes și pentru dezvoltarea anumitor drivere.

ODBC se bazează pe limbajul SQL, și funizează o interfață uniformă pentru seturi de date diferite, de la fișiere text, în care rubricele sunt despărțite prin virgulă până la sisteme de gestiune a bazelor de date multidimensionale și ierarhice.

ODBC include următoarele componente:

Aplicația care folosește baza de date

Administratorul ODBC

Gestionarul de driver

Apliația de instalare (ODBC Setup)

Driverele

Aplicația

Înainte ca apliația să poată folosi ODBC trebuie folosit suportul oferit de softul folosit pentru dezvoltarea aplicației care permite accesul la sursele de date ODBC

Administratorul ODBC

ODBC Administrator este o aplicație din Control Panel esențială pentru folosirea ODBC, care manevrează driverele instalate și administrează sursele de date. Fereastra principală a administratorului ODBC, Data Sources, conține o listă cu surse de date. Fiecare element din listă are un nume definit de utilizator urmat de numule driver-ului folosit de sursa respectivă. Fereastra administratorului ODBC este o interfață către sesțiunea ODBC, care stochează elemente de configarare ale surselor de date.

Gestionarul de driverere ODBC

Fișierul ODBC.dll conține gestionarul de driverere ODBC, componenta cea mai importantă a ODBC. Gestionarul de driverere controlează în primul rând configurația și parametrii driver-elor. Conectarea la o sursă de date se face prin intermediul gestionarului de drivere.

Drivere ODBC

Driverele ODBC sunt fișiere DLL (Dynamiv Linking Library) care furnizează interfața între alicația care va folosi baza de date și datele din baza de date. Standardul ODBC clasifică driverele după următoarele trei criterii: conformitatea cu interfața API, conformitatea cu gramatica SQL și tipul driver-ului.

Conformitatea cu interfața API limitează funcțiile care pot fi apelate de o aplicație ce utilizează ODBC. Funcțiile asigură elementele de bază pentru transmiterea parametrilor și accesul la rezultatele returnate de acestea.

Sursele de date ODBC

Sursele de date ODBC combină urmatoarele elemente: un driver ODBC pentru baze de date, o bază de date destinație, si caracteristicile bazei de date sau o conexiune la aceasta cum ar fi identificatorul și parola utilizatorului

Lucrul cu baze de date în Java

Aplicațiile Java utilizează JDBC (Java Database Connectivity) pentru accesul la un SGBD. JDBC este o interfață API care are rolul de a facilita conectarea la bazele de date, execută instrucțiunile SQL și preia rezultatele.

Java utilizează JDBC API pentru comunicarea cu JDBC Manager, care are rolul de a transmite informațiile de la aplicația Java la driver-ul JDBC. Driver-ul convertește instrucțiunile SQL într-un anumit protocol de acces specific unui anumit SGBD.

Din punctul de vedere al programatorului, interfața API este conservată indiferent de driver-ele SGBD sau JDBC. Intefața JDBC API și JDBC Manager asigură transparența aplicației de implementarea SGBD. Driver-ul JDBC obține accesul la un anumit SGBD utilizând un protocol de conexiune.

Pentru a distinge mecanismele de conectivitate din SGBD, JDBC utilizează un nume de subprotocol. Acesta permite driver-elor JDBC să fie folosite ca drivere ODBC. De exemplu, poate fi utilizat protocolul ODBC pentru a folosi o bază de date Microsoft Access. În acest caz protocolul ODBC este subprotocolul odbc utilizat de JDBC. Pe măsură ce sunt dezvoltate noi mecanisme de conectivitate, acestea trebuie să-și înregistreze subprotocolele lor la Java Soft, care le atribuie un nume unic.

O bază de date JDBC ce poate fi accesată cu ODBC și acceptată de Microsoft Acccess trebuie specificată într-un URL. Un URL (Universal Resource Locator) este un identificator universal de resurse care are rolul de a indica fișiere de resurse (un fișier text, multimedia, baze de date etc.) din Internet. Prin sintaxa sa, JDBC poate să indice o bază de date la care se dorește să se realizeze o conexiune. JDBC definește jdbc ca un prefix de protocol. Exemplul de mai jos ilustrează sintaxa unui URL de JDBC.

jdbc:<subprotocol>:<subnume>

Subprotocolul utilizează un subnume pentru a se conecta la o anumită bază de date. Sintaxa subnumelui diferă în funcție de subprotocolul specificat.

În cadrul unui URL de JDBC, poate fi precizat un serviciu de nume pe care îl va utiliza Java pentru a obține un nume de subprotocol și un subnume.

Dacă trebuie schimbat server-ul de baze de date, nu este necesară actualizarea programelor JDBC. Trebuie actualizat doar numele server-ului.

Conectarea la o bază de date

Pentru a realiza conectarea la o bază de date se utilizează metoda getConnection definită în clasa java.sql.DriverManagaer. Metoda are ca argumente un obiect URL și două șiruri de caractere. Următorul cod exemplifică modul de conectare la o bază de date.

Obținerea rezultatelor unei interogări

Pentru realizarea unei interogări în JDBC se construiește mai întâi o interogare SQL prin crearea unui obiect Statement. Clasa Statement face parte din pachetul java.sql. După crearea obiectului Statement se execută interogarea SQL prin apelarea metodei executeQuery() din clasa Statement. Metoda executeQuery() returnează un obiect ce conține rezultatul interogării. Pentru a extrage datele, se parcurge bucla repetitivă până când metoda next() returnează false. În cadrul buclei se apelează metoda getString() pentru a obține diferitele câmpuri din înregistrarea curentă. Codul următor ilustreză modul în care se obțin rezultatele unei interogări.

Lucrul cu baze de date în C#

Conectarea la o bază de date

Componente necesare conectării cu o bază de date

Pentru realizarea conexiunii cu o bază de date în C# este nevoie de cel puțin trei obiecte: un obiect oleDbConnection care să realizeze conexiunea cu sursa de date, un obiect oleDbDataAdapter pentru realizarea comunicării cu baza de date. Obiectele oleDbConnection și oleDbDataAdapter realizează comunicarea „fizică” cu baza de date.

Prin intermediul proprietății ConnectionString a unui obiect oleDbConnection, sunt setate valorile proprietăților necesare procesului de stabilire conexiunii cu o bază de date. Sintaxa pentru ConnectionString este un șir de perechi cuvânt cheie-valoare. Fiecare pereche cuvânt cheie-valoare este delimitată de „;” , iar șirul de perechi este delimitat de „”. Cuvintele cheie nu sunt case sensitive, dar valorile pot fi sau nu case sensitive, depinde de sursa de date.

Utilizarea fișierului de configurare pentru stabilirea conexiunii cu o bază de date

Un fișier de configurare conține setările pentru configurare utilizate de o aplicație și se scrie în format XML. Limbajul XML prezintă un format flexibil, standard deschis, care poate fi accesat de numeroase aplicații, pe multiple platforme. Aceasta înseamna că aplicațiile pot fi construite mai repede, mai robuste și mai ușor de întreținut.

Pentru crearea unui fișier de configurare, se acționeză butonul drept al mouse-ului pe numele aplicației și se selectează Add. Rezultatul acestei acțiuni este deschiderea unei noi ferestre, de unde se selectează Add New Item, acțiune ce are ca efect deschiderea unei noi ferestre de unde se selectează Application Configuration. Fișierul astfel creat are următoarea formă:

Atributul xml version specifică faptul că este vorba despre un fișier XML, iar atributul encoding specifică standardul unicode. Orice document XML trebuie să aibă un nod rădăcină. Pentru acest exemplu, nodul rădăcină este nodul configuration. Pentru crearea unui fișier de configurare este necesară adăugarea tag-urilor predefinite <appSettings>…</appSettings> și <add>. Atributul key ce aparține tag-ului add, specifică variabila ce va fi citită de aplicație, iar atributul value valoarea acestei variabile.

O regulă foarte importantă este că fișierul de configurare trebuie să se afle în același director cu aplicația. Numele fișierului de configurare trebuie să coincidă cu numele aplicației și trebuie să fie urmat de extensia .config. De exemplu, aplicația numită ServerApplication.exe trebuie să aibă fișierul de configurare numit ServerApplication.exe.config.

Un exemplul de fișier de configurare utilizat pentru a seta calea către o sursă de bază de date (necesară pentru realizarea unei conexiuni cu acea bază de date) este următorul.

Pentru accesarea din interiorul unui program a valorilor appsettings se folosește metoda GetValue() ce aparține clasei AppSettingsReader. Înainte de a folosi această metodă, trebuie incluse bibliotecile de funcții System.Configuration și System.Configuration.Assemblies.

Avantajul utilizării acestui fișier de configurare este următorul: dacă se schimbă calea către baza de date, atunci trebuie actualizată calea în fișierul de configurare, fără a mai fie nevoie de compilarea aplicației.

Obținerea rezultatelor unei interogări

Pentru a obține anumite înregistrări din baza de date, este novoie de un obiect oleDbCommand prin intermediul căruia este interogătă baza de date în scopul obținerii datelor necesare. Deasemenea, este necesar un obiect DataSet pentru putea prelucra datele. oleDbDataAdapter face legătura între DataSet și sursa de date. La un aplel al metodei Fill(), oleDbDataAdapter primește date din baza de date cu care populează DataSet-ul.

DataSet-ul este o abstractizare a unei baze de date relaționale. Un obiect DataSet conține nu doar înregistrările dintr-un tabel ci întreaga colecție de tabele și relațiile dintre acestea precum și metadatele necesare pentru descrierea relațiilor și a constrângerilor bazei de date.

Pot fi accesate ca propriectăți ale unui DataSet, obiecte DataTable și DataRelation. Proprietatea DataTable întoarce un obiect TablesCollection prin intermediul căruia poate fi accesat orice tabel din colecția de obiecte DataTabel. Un obiect DataTable poate fi instanțiat sau poate fi obținut ca rezultat în urma unei interogări a bazei de date.

DataTable are o serie de proprietăți publice printre care și proprietatea Columns (o colecție de coloane), care returnează obiecte de tip ColumnsCollection. Prin intermediul unui obiect ColumnsCollection pot fi accesate obiecte DataColumn. Fiecare obiect DataColumn reprezintă o coloană într-un tabel. O altă proprietate a unui obiect DataTable este proprietatea Rows, folosită pentru a returna înregistrările dintr-o tabelă. Se folosește proprietatea Rows pentru examinarea rezultatelor unei interogări a bazei de date.

În ADO.NET iterarea înregistrărilor nu se realizează într-un DataSet. Trebuie obținut mai întâi un obiect DataTable (ale cărui înregistrări dorim să le examinăm) iar apoi cu ajutorul unei instrucțiuni „foreach” este iterată colecția Rows.

Următorul cod sursă pune în evidență modul în care este realizată conexiunea la o baza de date, folosirea setărilor din fișierul de configurare și modul în care este obținut rezultatul unei interogări.

Lucrul cu baze de date în Delphi

În general o bază de date trebuie să dispună și de mijloace de accesare a ei. Companiile producătoare de software (pachete de programe) care pun la dispoziția programatorilor și mijloacele pentru crearea și gestiunea bazelor de date.

Accesul la sisteme SGBD prin mecanisme de conectare cu bazele de date deschise

Pentru definirea tuturor surselor de date ale aplicației Delphi care le utilizează, trebuie folosit utilitarul BDE Administrator. Acest utilitar oferă informațiile de conectare de care are nevoie aplicația pentru a avea acces la baza de date. Acesta realizează legătura fizică dintre aplicație și sistemul SGBD gazdă. Pentru crearea unei surse ODBC este necesară parcurgerea a două etape: definirea sursei ODBC și definirea sursei de date.

Definirea unei surse ODBC

Pentru definirea unei noi surse ODBC trebuie parcurși următorii pași:

Se lansează în execuție utilitarul BDE Administrator;

Se activează pagina etichetată Configuration;

Se selectează New din meniul Object; este deschisă caseta de dialog New ODBC Driver;

Se scrie numele driver-ului în interiorul câmpului Drive Name. Acesta este identificatorul pe care toate celelalte utilitare ale mediului Delphi îl vor folosi pentru a referi driver-ul.

Se selectează valoarea pentru câmpul ODBC Driver Name. În cazul în care aplicația folosește o baza de date Access, trebuie selectat din lista pusă la dispoziție: Microsoft Access Driver (*.mdb).

Se acționează butonul OK pentru a salva definiția driver-ului.

Definirea unei surse de date

Adăugarea unui driver este un proces care se desfășoară o singură dată, dar adăugarea de surse de date se poate face de mai multe ori pentru același driver. Utilitarul BDE Administrator ar trebui să fie întotdeauna primul punct de oprire în cadrul procesului de definire a unei surse de date. Definirea unei surse de date se face, în principal, pentru ca folosirea celorlalte facilități oferite de mediul Delphi pentru lucrul cu baze de date să fie mai ușoară.

Pentru a adăuga o nouă sursă de date trebuie urmăriți următorii pași:

Se lansează în execuție utilitarul BDEAdministrator;

Se selectează pagina Databases;

Se selecteză New din meniul Object. Se va afișa caseta de dialog New Database Alias;

Se selectează din lista derulantă valoarea pentru câmpul Alias Type. Implicit utilitarul BDE Administrator folosește numele “STANDARD” pentru a referi unele dintre tipurile de surse specifice sistemelor SGBD Paradox și dBASEIV. După ce s-a selectat valoarea câmpului în fereastra Databases este creat un alias implicit. Dacă se dorește, se poate schimba numele acestui alias selectând opțiunea Rename.

Se selectează Apply din meniul Object pentru a încheia acest proces. Utilitarul BDE Administrator va afișa în partea stângă a casetei de dialog toate alias-urile care au fost definite. Partea din dreapta arată parametrii pseudonimului selectat.

Cele mai multe multe dintre drivere necesită precizarea cel puțin a unei căi și a unui nume de bază de date. Cele de tip STANDARD nu necesită decât precizarea unei căi. Procesul de definire a sursei de date continuă cu stabilirea parametrilor pentru definirea sursei de date:

Se selectează alias-ul;

Se selecteză câmpul Path și se scrie calea către baza de date;

Se selecteză câmpul Database și se scrie numele bazei de date care urmează a fi folosită;

Se selectează câmpul User Name. În mod normal nu ar trebui introdus nimic deoarece acesta este numele pe care toate utilitarele Delphi îl vor afișa în cadrul ferestrei care va cere și parola. Facilitatea de protecție prin parolă este case sensitive.

În cele mai multe cazuri Delphi știe ce să facă cu datele îndată ce s-a definit sursa de date urmând pașii descriși anterior. Mai există câțiva parametrii opționali, dar care au un rol important:

Parametrul SQLQRYMODE permite definirea surselor informațiilor SQL. Acest parametru este important numai în situația în care se folosește atât o sursă SQL locală, cât și una pe un server. În cele mai multe cazuri valoarea acestui parametru este setată la valoarea NULL.

Parametrul LANGDRIVER se poate folosi pentru a schimba setul prestabilit de caractere pentru o bază de date. Modificarea acestei valori la configurare duce numai la schimbarea carecterelor pe care Delphi le folosește pentru afișarea informațiilor nu și a cuvintelor din tabel.

Parametrul SQLPASSTHRU MODE afectează modul în care Delphi permite accesul la baza de date. Există trei moduri de acordare a accesului la baza de date:

NOT SHARED dacă se dorește accesul exclusiv la baza de date

SHARED AUTOCOMIT permite partajarea bazei de date împreună cu mai mulți utilizatori. Avantajul acestei metode este că nu trebuie făcute manual modificările datelor. Dezavantujul este că nu poate oferi cu ușurință utilizatorului, tot în modulul de introducere a datelor, o modalitate de anulare a modificărilor pe care le-a făcut (acțiune de tip undo).

SHARED NOAUTOCOMMIT permite partajarea accesului la date cu toți utilizatorii, dar modificările făcute de un anumit utilizator nu se vor regăsi în baza de date până când acesta nu le confirmă. Acest mod se dovedește a fi util nu numai în situația în care se pune la dispoziția utilizatorului o facilitate de anulare a unei comenzi, ci și în situația în care se optează pentru acțiunea de tip batch.

Adăugarea unei baze de date

Următoarea succesiune de pași este utilă atunci când se dorește adăugarea unei baze de date.

Se lansează în execuție utilitarul Database Explorer;

Se acționează butonul drept al mouse-ului pe pictograma Database;

Din meniul afișat se selectează opțiunea New; se va activa fereatra New Database Alias;

Se selectează driver-ul dorit, din cadrul listei derulante și acționează butonul OK;

Utilitarul Database Explorer va afișa în partea stângă a ferestrei Database o nouă bază de date. Numele bazei este selectat. Imediat lângă numele bazei este poziționat cursorul de editare.

Se redenumește baza de date, prin scrierea unui nou nume;

Se selectează câmpul Path din partea dreaptă a ferestrei. Se scrie calea către directorul care conține datele.

Se acționează butonul drept al mouse-ului și se selectează opțiunea Apply din meniul afișat;

Dacă informațiile asociate pseudonimului sunt corecte, atunci utilitarul Database Explorer va aduna toate informațiile despre baza de date ce tocmai a fost definită. Dacă nu sunt corecte se va afișa un mesaj de eroare.

După ce a fost încheiat procesul de definire a pseudonimului, se poate deschide baza de date pentru a vizualiza obiectele pe care aceasta le conține.

Componentele necesare accesului la date

Pentru a putea accesa datele dintr-o bază de date prin intermediul mediului Delphi, trebuie ca baza de date care va fi accesată să poată accepta metodele de conectivitate cu bazele de date deschise (ODBC), interfața de programare a aplicațiilor independentede tipul bazei de date (IDAPI) sau să asigure un tip de driver nativ al mediului Delphi.

Principalele componente necesare accesului la date sunt:

TDataSource (sursa de date)

O sursă de date poate fi o tabelă, o interogare, o procedură – tot ceea ce face parte dintr-o bază de date. TDataSource este o componentă a mediului Delphi care realizează legătura cu sistemul SGBD (Sistemul de Gestiune al Bazelor de Date).

TTable (tabela)

O tabelă este o colecție de date, de mai multe obiecte din acceași clasă de obiecte. Fiecare proprietate a clasei de obiecte care este reprezentată în tabelă poartă numele de câmp al tabelei, iar mulțimea datelor despre un anumit obiect formează o înregistrare în tabelă. TTable este componenta mediului Delphi care permite accesul la înregistrările dintr-o singură tabelă ce face parte din baza de date.

TQuery

Permite interogarea bazei de date, sau a oricărei alte surse de date pentru a accesa anumite date, selectate pe baza unor criterii; interogarea se face de obicei cu ajutorul limbajului SQL (Structured Query Language). SQL este o modalitate standard de “conversație” cu o sursă de date.

APLICAȚIE DISTRIBUITĂ – DICȚIONAR ELECTRONIC

Introducere

Pentru a sublinia asemănările și deosebirile între suportul soft oferit de diferite medii de programare pentru programarea cu socket, voi prezenta o aceeași aplicație implementata în limbajele Java, C# și Delphi.

Aplicația se numește Dicționar electronic, folosește mecanisme de conectare la o bază de date, mecanisme de acces a datelor dintr-o bază de date și valorifică suportul soft pentru programarea cu socket oferit de clele trei limbaje de programare.

Baza alcătuirii dicționarului

Dicționarul electronic (în cazul nostru român-englez) cuprinde cuvintele unei limbi explicate în acceași limbă și apoi traduse într-o altă limbă. În realizarea acestui dicționar se impun două abordări: pe de o parte căutarea unei definiții a cuvântului (explicarea înțelesului) într-o formă în care să o înțeleagă ușor oricine și pe de altă parte, pentru a realiza concentrarea unor nuanțe de înțeles sau contopirea sub același cuvant titlu (românesc) a unor unități lexicale (cuvinte) diferite din punct de vedere al lingvisticii. O traducere acoperă sensurile obișnuite ale unui cuvânt, inclusiv cele figurate, iar în cazurile de necesitate se va recurge la indicații de domeniu (contexte).

Identificarea și documentarea tipurilor de entități pentru formulele de traducere

În sprijinul clasificării înțelesului cuvintelor se vor folosi formule care menționeaza cuvintele cu care cuvântul titlu explicat apare cel mai des legat în vorbire, într-o îmbinare liberă. În termeni de specialitate, acest fel de a cita s-ar putea numi “indicare a unor contexte specifice și/sau uzuale”. Un asemenea context specific poate da cuvântului un sens în oarecare masură diferit de cel cu care cuvântul apare în alte îmbinari libere ale aceluiași sens.

IndicațieContextRomână

Entitatea IndicațieContextRomână cuprinde abrevieri, definiții ale cuvântului, explicarea înțelesului și formule (în limba română) care menționează cuvintele cu care cuvântul titlu apare cel mai des legat în vorbire, într-o îmbinare liberă.

Toate acestea, în termeni de specialitate, se numesc „indicarea unor contexte specifice ”.

TraducereEngleză

Entitatea TraducereEngleză cuprinde traduceri (în limba engleză) ce acoperă sensuile obișnuite inclusiv, cele figurate, ale cuvintelor din limba română.

FormulăTraducere

Entitatea FormulăTraducere cuprinde cuvântul titlu, indicația de context asociată cuvântului titlu și traducerea formulei cuvânt titlu-indicație context.

Identificarea tipurilor de relații

Relațiile dintre entitățile prezentate anterior sunt descrise în figura de mai jos.

Structura de ansamblu a aplicației

Aplicația este modelată client-server, cele două programe de bază se află, de regulă, pe calculatoare diferite. Unul dintre programe are rolul de a oferi servicii (serverul), iar celălalt de a solicita aceste servicii (clientul). Solicitarea unui serviciu server-ului, presupune parcurgerea următoarelor faze:

Conectarea este faza în care clientul se conectează la server prin TCP

Crearea unui Server Thred pentru fiecare client

Comunicare/Ascultare pentru o nouă conexiune. – Clientul comunică cu server-ul, dar în același timp server-ul ascultă canalul pentru noi conexiuni.

În același timp, clientul comunică cu server thred-ul asociat și server-ul ascultă canalul fiind gata să realizeze noi conexiuni. Server-ul poate comunica cu mai mulți clienți în același timp și la același port. Teoretic numărul conexiunilor concomitente este nelimitat. În realitate acesta depinde de diferiți factori.

Pentru a putea comunica clientul și server-ul trebuie să cunoască un protocol de comunicare.

Protocolul de comunicare

Clientul trimite server-ului o cerere iar server-ul o rezolvă și trimite rezultatul clientului. Aplicația implementează un protocol simplu de comunicare cu patru comenzi: CONNECT, REQUEST THE FALLOWINGING FORMULA, REQUEST ALL DATA FROM DICTIONARY și DISCONNECT. Sintaxa generală a unei comenzi este:

user_name ":" comandă ":" [parametru comandă ] delimitator sfârșit comandă

Sintaxa reprezintă o linie de comandă ce conține: numele utilizatorului care a trimis comanda, urmat de numele comenzii și eventual un parametru (doar în cazul comenzii REQUEST THE FALLOWING FORMULA). Pentru a marca sfârșitul unei comenzi se folosește un delimitator de sârșit de comandă. Secvența următoare este un exemplu de comunicare între un client c și un server s.

c:<username>:<CONNECT>:

(clientul trimite comanda CONNECT prin care cere server-ului să-i accepte o conexiune)

s:CONNECT

(trimite clientului mesajul CONNECT, ceea ce înseamnă că a fost acceptată conexiunea, și server-ul așteaptă cereri)

c:<username>:<REQUEST ALL DATA>:

(clientul trimite cererea „REQUEST ALL DATA”, ceea ce însemnă că dorește toate formulele de traducere din dicționar)

s:<REQUEST ALL DATA>

(Server-ul trimite clientului rezultatele cererii REQUEST ALL DATA )

c:<username>:<DISCONNECT>:

(clientul s-a deconectat de la server, închide conexiunea cu server-ul )

s:<DISCONNECT>

(sever-ul închide conexiunea pentru clientul username )

Implementarea aplicației

Versiunile aplicației în Java și C# au în comun cele descrise în paragarfele anterioare ale acestui capitol. În continuare vor fi evidențiate aspectele implementaționale ale aplicației în cele trei limbaje de programare.

Implementarea aplicației în Java

Aplicația dezvoltată cu limbajul Java, este o aplicație cu server, concurent astfel încât pentru fiecare cerere de conectare acceptată de server se lansează un fir de execuție care se ocupă de comunicarea dintre client și server. Dacă sever-ul ar avea un singur fir de control, atunci numai un singur client ar putea interacționa cu server-ul la un moment dat. Server-ul este multifir pentru a putea procesa mai multe conexiuni client-server simultan.

Partea server a aplicației permite urmărirea în timp a procesului de conectare a clienților, a cererilor solicitate și rezultatul trimis de server clienților.

Partea client a aplicației este un program multifir și oferă utilizatorilor o interfață garfică prin intermediul căreia pot solicita conectarea cu server-ul și formule de traducere pentru cuvinte.

Descrierea părții server a aplicației Java

Partea server a aplicației utilizează trei clase pentru a a răspunde cererilor clienților: clasa Server – responsabilă cu acceptarea cererilor de conexiune ale clienților, clasa ExecuteCommand – responsalbilă pentru comunicarea client-server și clasa AplicatiaServer a cărei sarcină este de a realiza conexiunea cu baza de date și de a interoga baza de date pentru obținerea formulelor de traducere a cuvintelor titlu.

Prima sarcină pe care trebuie să o îndeplinească server-ul este să creeze un socket Server, iar apoi să aștepte cereri de conectare din partea clienților. Dacă un client solicită o cerere de conexiune și server-ul acceptă cererea de conexiune a clientului, atunci server-ul lansează un fir de executie pentru a controla comunicarea client-server.

Următorul fragment de cod ilustrează considerațiile făcute mai sus.

Pentru realizarea comunicarii cu clienții, server-ul crează o instanță a clasei ExecuteCommand.

Clasa ExecuteCommand extinde clasa Thread și este responsabilă cu comunicarea dintre clientul a cărei cerere de conexiune a fost acceptată și server.

Constructorul clasei preia ca parametru un obiect Socket și inițializează fluxurile de intrare și de ieșire pentru realizarea schimbului de date dintre clientși server.

Metoda run() a clasei ExecuteCommand implementează protocolul de comunicare dintre client și server. Cererile clienților sunt preluate de fluxul de intrare, apoi sunt „procesate” utilizând un obiect StringTokenizer care interpretează cererea clientului conform protocolului de comunicare (identifică numele utilizatorului care a lansat cererea, tipul cererii și eventual parametrul în cazul în care a fost solicitată o cerere de fitrare pentru formulele de traducere dicționar).

După etapa de procesare a cererii, server-ul rezolvă cererea clientului. În cazul în care clientul solicită o cerere de formule de traducere, acesta execută o interogare a bazei de date creând mai întâi un obiect ApicatiaServer, apoi să apelează una din metodele responsabile cu interogarea bazei de date ale casei AplicatiaServer all() sau filter().

Implementarea metodei run() a clasei ExecuteCommand este ilustrată de următorul fragment de cod:

Clasa AplicatiaServer realizează conexiunea cu baza de date, iar cele două metode ale clasei all( ) și filter() sunt responsabile cu interogarea și obtinerea rezultatului interogării bazei de date. Metoda all() întoarce ca rezultat formulele de traducere din evidența bazei de date.

Metoda filter() are un parametru string – un sir de careactere cu care incearcă să-l potrivească cu cuvinte tiltu din dicționar. Dacă găsește astfel de potriviri atunci întoarce ca rezultat formulele de traducere pentru cuvintele titlu pentru care s-au găsit potriviri.

Descrierea părții client a aplicației Java

Partea client este un program multifir, implementează interfața Runnable și folosește o fereastră JFrame pe care sunt plasate conponentele necesare interfeței grafice a utilizatorului (butoane, etichete si casete de editare ).

Componentele grafice ale interfeței sunt obiecte Swing și sunt create în metoda creazaComponente() a clasei Client. Metoda creazaComponente() întoarce un obiect Component care trebuie adăugat mai întîi într-un container intermediar denumit panou de conținut și reprezintă aria completă a cadrului în care sunt plasate componentele. După definirea panoului de conținut prin apelul metodei setContentPane(), acesta este atașat obiectului JFrame.

Pentru a inițializa o conexiune cu sever-ul, aplicația client trebuie să creeze un obiect Socket, pentru a crea un socket și a-l conecta la calculatorul și portul specificate ca parametri. Pentru a transmite cererea de conexiune server-ului, este necesar ca utilizatorul să specifice adresa IP și numărul de port care identifică server-ul și apoi să acționeze butonul Conectare.În urma acționării unui buton, Java generează un eveniment action care trebuie procesat. Butonul Conectare are asociată o metodă care prelucrează evenimentele și care este apelată automat atunci când are loc un eveniment acțiune. După acționarea acestui buton, aplicația client trimite server-ului o cerere de conexiune, inițializează fluxurile de intrare și de ieșire și lansează un fir de executție care controlează comunicarea cu server-ul .

Dacă cererea de conexiune este acceptată de server, atunci clientul poate solicita cereri de formule de traducere. Pentru aceasta utilizatorul trebuie să introducă cuvântul titlu în caseta de editare și să acționeze tasta enter.

La fel ca și butonul Conectare caseta de editare are o metodă care tratează evenimentul de acționare a tastei enter. După procesarea acestui eveniment, clientul trimite server-ului cererea de formule de traducere pentru cuvantul specificat de utilizator în caseta de editare.

Server-ul rezolvă cererea și trimite rezultatul clientului. Rezultatul trimis de server este procesat în metoda run() a aplicației client. Metoda run() preia rezultatul din fluxul de intrare, procesează rezultatul trimis de server și îl afișează utilizatorului. Mai jos este prezentat un fragment din codul metodei run() care evidențiază cosiderațiile anterioare.

Fiecare din clasele prezentate, cele utilizate de server și cele utlizate de client, sunt memorate în fișiere separate. Server-ul este o aplicație consolă, iar partea client implementează o interfață grafică pentru utilizator. O imagine a ecranului unui client în cursul rulării aplicației este:

Imaginea ecranului server-ului în timp ce rezolvă cereri solicitate de clienți:

Implementarea aplicației în C#

Aplicația dezvoltată cu ajutorul limbajului de programare C#, este un exemplu de aplicație cu server concurent. Server-ul ține evidența tuturor clienților conectați, a cererilor solicitate și a serviciilor oferite clienților la un moment dat. Atât partea server cât și partea client sunt aplicații Windows. Partea client a aplicației permite ulilizatorilor să solicite conecatrea la server pentru ca apoi să poată accesa datele din dicționar.

Descrierea părții server a aplicației C#

Server-ul utilizează două clase, TCPServer și TCPServerSession, pentru a gestiona conexiuni multiple cu clienții. TCPServer ascultă canalul pentru eventuale cereri de conexiune cu clienții. Dacă o conexiune este acceptată, clasa TCPServer crează o instanță a clasei TCPServerSession pentru a realiza comunicarea cu clientul a cărei cereri de conexiune a fost acceptată. Fiecare instanță a clasei TCPServerSession va fi controlată de un thread – fir de execuție. Clasa TCPRemoteCommandProcessor de pe partea client a aplicației, lansează o cerere, conform protocolului de comunicare descris într-un paragraf anterior. Această cerere este prreluată de clasa TCPServerSession. Cererea primită este mai întâi interpretată de clasa care implementează interfața CommandProcessor, iar apoi este executată de delegatul executeCommand().

S-a introdus o noțiune nouă, aceea de delegat, pentru care se impun câteva explicații care să definească această noțiune. Evenimentele „se întâmplă ceva” și delegații sunt strâns legate între ele deoarece răspunsul la un astfel de eveniment este tratat de un EventHandler, care în C# implementează un delegat. Un delegat este un tip referință folosit pentru a încapsula o metodă cu un anumit antet (tipul parametrilor formali și tipul return). Orice metodă care are același antet poate fi legată la un anumit delegat. Un exemplu foarte simplu care lămurește utilitatea delegaților este următorul:un buton care a fost acționat știe că trebuie să anunțe un obiect despre acest eveniment dar nu știe pe care anume. Decât să se lege butonul de un obiect particular, butonul va declara un obiect pentru care clasa interestă de evenimentul de apăsare oferă o implementare care tratează evenimentul.

Metoda care implementează delegatul executeCommand() este metoda execute() și aparține interfeței CommandProcessor.

Cererile soliicitate de clienți și modul în care server-ul răspunde acestora este evidențiată în diagrama de secvență realizată cu ajutorul UML:

Funcționalitatea aplicației client-server va fi descrisă odată cu descriera claselor, în paragrafele următoare.

Clasa TCPServerSession

Clasa TCPServerSession are un constructor care inițializează o sesiune a server-ului cu un client. Clasa mai conține două metode: metoda close() – care închide sesiunea și metoda run() – care ascultă canalul pentru noi conexiuni.

Constructorul clasei primește ca parametru un socket – pentru a asculta canalul și pentru a răspunde cererilor și un delegat executeCommand() – pentru a interpreta cererile primite de la clienți.

Metoda run() conține o buclă while în care citește cererile venite de la clienți, iar apoi apelează delegatul executeCommad() pentru a interpreta cererile clienților. Delegatul returnează un rezultat care este trimis clientului care a lansat cererea. Ieșirea din bucla while se face când server-ul închide sesiunea (este apelată metoda close()) sau când delegatul returnează valoarea false.

Codul sursă al metodei run() a clasei TCPServerSession

Clasa TCPServer

Clasa TCPServer implementeză un server care gestionează conexiuni multiple cu clienții folosind câte o sesiune pentru fiecare client care solicită o conexiune cu server-ul. Sesiunile sunt instanțe ale clasei TCPServerSession prezentată anterior.

Clasa are un constructor și două metode: metoda close() – care închide server-ul și metoda run() – care ascultă canalul pentru a accepta cererile de conexiune ale clienților.

Contructorul clasei crează mai întâi două liste (instanțe ArrayList). Prima listă conține toate sesiunile deschise la un moment dat, iar cea de-a doua listă ține evidența thread-urilor lansate pentru controlul sesiunilor client-server. În continuare constructorul crează un socket TCPListener pentru a asculta canalul pentru noi cereri de conexiune din partea clienților la numărul de port specificat ca parametru. Pe langă numărul de port, constructorul clasei mai are un parametru – delegatul executeCommnad(). Când server-ul stabilește o sesiune cu un client, crează o instanță a delegatului executeCommand() pentru a interpreta cererile clienților. În cele din urmă, construtorul lansează un thread pentru „a controla” sesiunea client-server deschisă. Thread-ul execută metoda run().

Metoda run() ascultă canalul pentru a accepta noi cereri de conexiune. Dacă primește o cerere de conexiune și server-ul o acceptă atunci crează o sesiune cu clientul. Metoda se execută cât timp serverul este activ.

Clasa ServerApplication

Acestă clasa oferă o interfață grafică utiliztatorului pentru a putea urmări evoluția în timp a conectărilor clienților, cererile clienților și răspunsurile server-ului la aceste cereri.

Clasa ServerApplication implementează interfața CommandProcessor și are trei metode: metoda execute() și încă două metode, giveAll() și filter(), prin intermediul cărora este interogată baza de date la care este conectat server-ul. Interogarea bazei de date se face cu limbajul SQL.

Structura clasei ServerApplication

Metoda giveAll() întoarce ca rezultat toate formulele de traducere din dicționar, iar metoda filter() filtrează formulele de traducere în funcție de parametrul primit – cuvântul titlu pentru care a fost solicitată cererea formulelor de traducere.

Rezolvarea unei cereri este implementată în metoda execute() a clasei ServerApplication. Sunt doar patru tipuri de cereri pe care le poate solicita un client: conectare la server – CONNECT, formulele de traducere din dicționar – REQUEST ALL DATA FROM DICTIONARY, anumite formule de traducere pentru un cuvânt tiltlu – REQUEST THE FALLOWING FORMULA și deconectarea de la server – DISCONNECT.

Codul sursă al metodei execute() implementată de clasa ServerApplication.

Dacă server-ul primește o cerere de conexiune, acesta adaugă numele utilizatorului în lista clienților conectați la server, iar dacă primește o cerere de deconectare din partea unui client care are deschisă o sesiune, server-ul scoate utilizatorul din lista clienților conectați și nu-i mai permite acestuia să solicite alte cereri până când nu va solicita întâi o cerere de conexiune.

Descrierea părții client a aplicației C#

Funcționalitatea părții client a aplicației client-server este susținută de implenentarea interfeței grafice destinată utilizatorilor dicționarului.

Clasa TCPRemoteCommandProcessor

Clasa TCPRemoteCommandProcessor implementează interfața CommandProcessor și are o metodă close() care închide conexiunea clientului cu server-ul. Interfața CommandProcessor are rolul de a formula cereri către server și de a interpreta rezultatul trimis de server pentru a fi apoi afișat utilizatorilor.

Codul sursă al metodei execute() inplementată de clasa TCPRemoteCommandProcessor.

Clasa ClientApplication

Clasa ClientApplication implementează interfața grafică pentru utilizator și crează o instanță a clasei TCPRemoteCommandProcessor pentru a prelua cererile clienților, a le trimite server-ului și pentru a primi răspunsul la cererile solicitate.

Codul sursă al metodei connectClick() care solicită cererea de conexiune cu server-ul.

Primul pas pe care trebuie să-l facă utilizatorul pentru a avea acces la formulele de traducere din dicționar este să specifice adresa și numărul de port la care server-ul așteaptă cererile lui. Al doilea pas pe care trebuie să-l facă este să trimită sever-ului o cerere de conexiune la adresa și portul specificate la primul pas. Dacă cererea de conexiune este acceptată de server, utilizatorul poate solicita formule de traducere pentru cuvinte titlu, cât timp este deschisă sesiunea cu server-ul. După o cerere de deconectare de la server, utilizatorul nu mai poate solicita server-ului alte cereri, decât dacă solicită mai întăi o cerere de conexiune.

O imagine a ecranului unui client în cursul rulării aplicației este:

Imaginea ecranului server-ului în timp ce rezolvă cereri solicitate de clienți:

Implementarea aplicației cu suportul oferit de mediul Delphi

Activitațile sistemului

Cele două programe (client și server) ale aplicației trebuie să cunoască protocolul după care are loc comunicarea. Protocolul pentru solicitarea cererilor către server și primirea rezultatelor este următorul:

Clientul lansează cererea, care este transmisă componentei sever într-un format standard

În funcție de cererea primită, componenta sever „traduce” cererea în instrucțiuni SQL pe care le trimite server-ului de baze de date.

Serverul de baze de date execută instrucțiunile SQL și rezultatul îl returnează server-ului.

Server-ul expediază rezultatul într-un anumit format recunoscut de client.

Componenta „traduce” rezultatul de la server și îl afișează utilizatorului.

Clientul poate alege serviciile oferite de server selectându-le din meniul ferestrei principale al aplicației client.

Descrierea părții client a aplicației Delphi

Clientul este cel care lansează cererile către server. Aplicația executată de client are rolul de: prezentare a unei interfațe grafice pentru utilizator, formulare a cererilor către server și de afișare a rezultatelor pe care le primește de la server. La lansarea sa în execuție, programul client execută urmatoarele activități:

Creează o conexiune TCP cu server-ul

Codul sursă pentru stabilirea conexiunii

Acceptă intrarea utilizatorului și trimite într-un format standard cererile către server

Codul sursă pentru trimiterea cererii către server (cere formula de traducere pentru un cuvânt titlu).

Acceptă ieșirea de la server într-un format standard și afișează rezultatul utilizatorului

Codul sursă pentru afișarea rezultatului trimis de server

Descrierea părții server a aplicației Delphi

Server-ul este dedicat păstrării, administrării și regăsirii datelor. Componentele specifice lucrului cu baze de date, de pe server „reacționează” la interogările clientului (care de această dată este aplicația server, pentru că solicită serviciile acestuia) executând instucțiunile SQL prin care clientul solicită regăsirea anumitor date în baza de date și apoi returnează rezultatul cererii. Atunci când server-ul este gata să accepte cereri, execută urmatoarele acțiuni:

Așteaptă cererile într-un format recunoscut și le rezolvă

Expediază rezultatul cererii într-un format recunoscut de client.

Codul sursă în care server-ul trimite rezultatul cererii unui client este:

Schimbul de informații dintre componentele aplicației, și stările prin care trece sistemul sunt reprezentate în diagrama de stare a sistemului realizată cu ajutorul UML-ului (Unified Modeling Language).

Bibliogarfie

Ioan Jurca, Programarea rețelelor de calculatoare, Editura de Vest Timișoara, 2001

Florian M. Boian , Programarea distribuită în Internet – metode și aplicații, Editura Albastră, Cluj Napoca, 2000

Socket Library Functions, Documentation, URL: http://www.cisco.com/univercd/cc/td/doc/product/software/ioss390/ios390sk/sklibfun.htm

Tanenbaum, Rețele de calculatoare, Computer Press Agora, Cluj Napoca, 1997

Brian Bagnall, Philip Chen, Stephen Goldberg, C# for Java Programmers, solutions@ syngress.com

Adrian Turtschi, Jason Werry, Greg Hack,C# .NET Web Developre’s Guide, solutions@ syngress.com

Rebecca M Riordan, Microsoft ADO .NET Step by Step, Microsoft Press, 2002

Jesse Liberty, C# Programing, O’Reilly, 2001

Chris H. Pappas, William H. Murray, C# pentru programarea Web, Editura B.I.C. ALL, Timișoara , 2002

Marck C. Chan, Steve W. Griffith, Anthony F. Iasi, JAVA 1001 secrete pentru programatori, Editura Teora, 2000

Laura Lemay, Rogers Cadenhead, Java 2 fără profesor în 21 de zile, Editura Teora, 2000

Mihai Oltean, Programarea avansată în DELPHI, Editura Albastră, Grupul Microinformatica, Cluj Napoca, 2000

Kovacs Sandor, Delphi 3.0 Ghid de utilizare, Editura Albastră, 1998

Eric I. Nailburg, Robert A., UML for Database Design, Addison Wesley, 2001

Similar Posts