Cuprins

1. Introducere .....................................................................................................
1.1. Modelul client - server ......................................................................................................... 1.2. URL. Scheme URL ................................................................................................................. 1.3. Hipertext, hiperlegătură, hipermedia ............................................................................. 1.4. Protocolul HTTP (Hypertext Transfer Protocol) ..........................................................

2. FTP şi poşta electronică ...............................................................................
2.1. Serviciul FTP – transfer de fişiere .................................................................................. 2.1.1. Server FTP ................................................................................................................ 2.1.2. Client FTP ................................................................................................................. 2.2. Serviciul de poştă electronică – e-mail ........................................................................... 2.3. Exerciţii ..................................................................................................................................

3. Servere WEB ..................................................................................................
3.1. Introducere ............................................................................................................................ 3.2. IIS ........................................................................................................................................... 3.3. Exerciţii IIS ......................................................................................................................... 3.4. NCSA ....................................................................................................................................... 3.5. Apache .................................................................................................................................... 3.6. Exerciţii NCSA, Apache .....................................................................................................

4. Utilitare TCP - IP ..........................................................................................
4.1. Utilitare TCP - IP .................................................................................................................. 4.2. Testarea unei configuraţii TCP - IP ................................................................................. 4.3. Exemple de folosire a unor utilitare TCP - IP ...............................................................

5. Adresare IP ....................................................................................................
5.1. Clase de adrese ..................................................................................................................... 5.2. Exerciţii rezolvate ...............................................................................................................

6. Comunicare client – server la nivel de socket .........................................
6.1. Introducere ............................................................................................................................ 6.2. Interfaţa socket .................................................................................................................. 6.2.1. Comunicaţie client – server TCP - IP ................................................................. 6.2.2. Comunicaţie client – server UDP - IP ................................................................ 6.3. Exemplificări .........................................................................................................................

4 5 6 8 9 10 10 10 11 12 18 19 19 19 21 22 26 27 30 30 33 34 35 35 39 43 43 44 48 52 53 65 68 68 71 81 81

7. Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE ......................................................................................................................
7.1. Nivelul de acces la date ....................................................................................................... 7.1.1. Apelarea procedurilor stocate pe SQL Server ............................................... 7.1.2. Vizualizarea accesului la baza de date .............................................................. 7.2. Nivelul logicii aplicaţiei ....................................................................................................... 7.2.1. Apelarea procedurilor la distanţă .......................................................................

7.2.2. Serializarea tipurilor de date complexe .......................................................... 7.2.3. Apelarea serviciilor WEB în mod asincron ....................................................... 7.2.4. Publicarea unei componente ca serviciu WEB ................................................. 7.2.5. Servicii WEB virtuale ............................................................................................ 7.2.6. Autentificarea şi autorizarea accesului ........................................................... 7.3. Nivelul de prezentare .......................................................................................................... 7.3.1. Construirea unei imagini într-o pagină ASP.NET ............................................. 7.3.2. Apelarea unei componente dintr-un servlet .................................................... 7.3.3. Definirea unui Custom Tag în JSP ..................................................................... 7.4. Interoperabilitatea platformelor .NET şi J2EE ..........................................................

Bibliografie ..........................................................................................................

86 90 94 99 103 105 105 107 110 113 116

1 Introducere
Reţelele de calculatoare s-au dezvoltat spectaculos în ultimii ani, datorită evoluţiei tehnologiilor hardware, software şi de interconectare. Tehnologii de mare viteză au dus la utilizarea reţelelor de calculatoare în toate domeniile vieţii socio-economice, cu rezultate deosebite. Clasificarea reţelelor de calculatoare, după criteriul distanţei, în LAN (Local Area Network), MAN (Metropplitan Area Nerwork) şi WAN (Wide Area Network) este foarte cunoscută astăzi, iar Internet-ul este accesibil aproape oricui. Extinderea utilizării Internet-ului a dus la dezvoltarea serviciilor şi aplicaţiilor distribuite, prezentate pe scurt în acest material. Serviciile Internet cele mai răspândite sunt: WWW, poşta electronică (e-mail), transferul fişierelor (ftp), conectarea la distanţă (telnet, ssh). Unul dintre cele mai folosite servicii Internet este serviciul Web. WWW (World Wide Web), cunoscut şi sub denumitrea de Web sau W3, reprezintă serviciul Internet care permite navigarea pe colecţii de documente multimedia (hypertexte), din diferite reţele, calculatoare prin hyperlegături, utilizând o interfaţă comună (browser-ul). Caracteristici: Se deosebeşte de alte servicii Internet deoarece, prin concepţia sa, înglobează alte servicii ca: FTP, Gopher, Telnet, News. Reprezintă subnivelul superior al nivelului aplicaţie. Face apel la următoarele elemente: o URL (Universal Resource Locators) identificatorul uniform al resurselor; o HTTP (HyperText Transfer Protocol); o HTML (HyperText Markup Languages). Serviciul Web se deosebeşte de alte servicii Internet prin faptul că înglobează unele dintre ele, cum ar fi FTP, Gopher, Telnet, Wais, News. 4

Reţele de calculatoare

1.1 Modelul client-server Cel mai răspândit model de comunicare în Internet, având la bază protocolul TCP/IP, este modelul client-server, model după care funcţionează toate aplicaţiile şi serviciile Internet. Clientul, de obicei, rulează pe calculatorul utilizatorului şi este folosit pentru a accesa informaţii sau alte aplicaţii din cadrul reţelei. Browser-ul: emite cererile şi recepţionează datele care vor fi afişate; formatează documentele ţinând cont de tag-urile HTML; afişează documentele. Exemple: Netscape, Internet Explorer, Lynx, HotJava, Mosaic. Serverul rulează, de obicei, pe un calculator centralizator sau aflat la distanţă, furnizând sau oferind informaţii/servicii clienţilor. Exemple: Apache, NCSA, IIS (daemon httpd).
Client (cerere/răspuns) Server

Figura 1.1 Modelul client-server Modelul client-server are la bază un protocol simplu, fără conexiune de tipul întrebare-răspuns. La implementarea modelului client-server se ţine seama de: adresarea proceselor server; tipul primitivelor utilizate în transferul mesajelor (sincrone/asincrone, cu/fără tampon, fiabile/nefiabile). Clientul şi serverul se pot găsi în acelaşi nod, când se utilizează mecanisme de comunicaţie locală sau în moduri diferite, când se utilizează mecanisme de comunicaţie în reţea. 5

Introducere

1.2 URL. Scheme URL Generalităţi: S-a pus problema unui sistem standardizat de regăsire uniformă a resurselor. Pentru a se putea referi în mod standard, în cadrul aplicaţiei Web, orice tip de document (text, imagine, sunet), a fost creată specificaţia URL (Uniform Resource Locator). Prin URL se înţelege o descriere completă a unui articol, ce conţine localizarea acestuia, articolul putând fi un fişier de pe maşina locală, sau altul din orice parte a Internet-ului. Suportul principal pentru URL îl reprezintă documentul de tip hipertext. Acest document conţine link-uri (legături la alte servere) normalizate de tip URL. Hipertextul se descrie printr-un limbaj foarte simplu, care se poate implementa în orice fişier ASCII, numit html. Sintaxa generală Un URL complet constă într-o schemă, urmată de un şir de caractere cu format special, care este o funcţie a respectivei scheme. [URL:] schema-de-denumire | sir URL-ul cuprinde trei părţi: un cod pentru a identifica protocolul de transfer ce va fi utilizat; adresa pentru a identifica host-ul pe care sunt stocate fişierele; un descriptor de cale pentru amplasarea punctului (locaţiei) pe acea maşină. URL-ul trebuie să înceapă cu numele schemei, urmat de “:”, apoi adresa locaţiei unde se găseşte resursa, încadrată între caracterele: “//” şi “/” şi opţional un nume de utilizator şi o parolă.

6

Reţele de calculatoare

Pentru protocoalele Internet avem următoarea formă generală: schema://[ [nume-utilizator] [:parola]@ ] nume-de-domeniu-Internet [:număr-port] [/lista-de-directori] [/nume-de-fisier] Dacă nu se specifică numele de utilizator şi parola corespunzătoare, atunci înseamnă că avem de-a face cu un utilizator anonimous. Conform cu definiţia BNF a sintaxei, există câteva scheme URL standard, care vor fi prezentate în tabelul 1.1. Scheme URL standard Tabelul 1.1 PROTOCOL DESCRIERE MOD DE LUCRU HTTP Protocol de transfer http://host[:port][/cale][?cautare] hipertexte FTP Protocol de transfer de ftp://[user[:parola]@]host/cale fişiere MAILTO Adresa de E-mail mailto:user@host NEWS Ştiri Usenet news:grup-discutii NNTP Ştiri Usenet pentru acces nntp:grup/cifre local NNTP FILE Acces la fişiere file://host/cale TELNET Referire la o sesiune telnet://host[:port] interactivă Tipuri de URL–uri: relative - exp: „doc/document_html”; absolute - exp: „met_acces://nume_server[:port]/cale/”. Termeni UR*: URI – Universal Resource Identifier este numele pentru identificatorul generic WWW. Specificaţiile URI definesc sintaxa pentru codificarea arbitrară a schemelor şi conţin o listă a acestor scheme.

7

Introducere

URL – Uniform Resource Locator este o reprezentare compactă a locaţiei şi a metodei de acces pentru resursele disponibile pe Internet. Când este conţinut într-un document de bază, URL-ul în forma sa absolută conţine un tip de informaţie care este deja cunoscută de serverul destinaţie, facilitând astfel transferul fişierelor. URN – Uniform Resource Name este o schemă particulară care include autenticitate, reproducere şi disponibilitate pentru URL-uri, nefiind un URL în adevăratul sens al cuvântului. URC – Uniform Resource Characteristics reprezintă un set de atribute care descriu un obiect, cum ar fi: autorul, publicistul, tipul de dată, data calendaristică, elemente de copyright şi dimensiunea documentului. 1.3 Hipertext, hiperlegătură, hipermedia Hipertext este un text ce conţine legături numite hiperlegături sau ancore, către alte texte sau informaţii. Urmărind aceste legături, cititorul se poate deplasa în interiorul unui document sau de la un document la altul. O hiperlegătură leagă textul curent cu altă informaţie aflată undeva în Internet sau cu o nouă locaţie din cadrul documentului curent. Hiperlegăturile sunt evidenţiate în cadrul browser-ului în mod grafic cu o culoare şi/sau subliniate. Un singur click cu mouse-ul pe fiecare frază superluminată şi browser-ul va urmări automat acea legătură şi va afişa pe ecran o nouă informaţie. Trebuie specificat că nu este necesară citirea linie cu linie a acestui hipertext. Umărind un anumit set de legături, cititorul poate naviga înainte sau înapoi în cadrul unui singur document, în timp ce alte legături îl pot purta în oricare punct din cadrul oricărui alt document din cadrul Web-ului. În prezent, termenul hipertext semnifică doar textul de bază al documentului. Multe alte documente din Web sunt hipermedia, conţinând imagini şi legături cu grafice, animaţie şi sunete.

8

Reţele de calculatoare

1.4 Protocolul HTTP (Hypertext Transfer Protocol) Caracteristici: Este cel mai important şi cel mai des folosit protocol al Reţelei Mondiale (Web). Este un protocol rapid, special proiectat pentru mediul interactiv, hipermedia din Web. Este un protocol de nivel aplicaţie, ce oferă uşurinţa şi viteza necesare dezvoltării aplicaţiilor hipermedia. Este un protocol generic, orientat obiect, care poate fi folosit cu uşurinţă de multe task-uri, cum ar fi servere de nume şi sisteme de management distribuit, cu extensiile cerute de metodele sale. Permite tipărirea şi negocierea reprezentării datelor, construirea de sisteme independente de date care vor fi transferate. Este orientat pe conexiune şi asigură recepţionarea sigură a pachetelor de date, oferind şi o metodă de control al fluxului între hosturile sursă şi destinaţie. Este construit peste serviciile protocolului TCP/IP, care garantează că datele au fost recepţionate corect, nu au fost pierdute, duplicate sau recepţionate în altă ordine faţă de cea în care au fost transmise. Procesul de recepţie are controlul asupra vitezei la care se recepţionează şi se transmit datele, prin mecanismul de fereastră glisantă. Când se startează o aplicaţie, modulul HTTP al calculatoruluiclient şi modulul HTTP al calculatorului-server încep să comunice unul cu altul. Aceste două module (client şi server) conţin informaţii de stare care definesc un circuit virtual. Acest circuit virtual consumă resursele atât ale serverului, cât şi ale clientului. Circuitul virtual este full-duplex, datele pot circula în ambele direcţii simultan.

9

2 FTP şi poşta electronică
2.1 Serviciul FTP - Transfer de fişiere Caracteristici: Permite transferul fişierelor de orice tip (fie ele binare sau de tip text) între două calculatoare din Internet. Este bazat pe un sistem de autentificare a utilizatorilor. Există servere publice, sau cele care oferă FTP anonim. Există un cont special, numit anonymous (sau ftp), care nu este protejat prin parolă şi pentru care majoritatea serverelor moderne cer introducerea ca parolă a adresei de poştă electronică a utilizatorului client. În mod normal, pentru accesul la documentele de pe un server FTP, un utilizator trebuie să deţină un nume de cont şi o parolă validă pentru respectivul server. Parola este transmisă în clar prin reţea, permiţând oricărui utilizator local care are acces la un program de monitorizare a reţelei să o afle. Din acest motiv, transferul de informaţii prin FTP se va efectua doar în zone în care se ştie că nu este posibilă monitorizarea reţelelor de către orice utilizator. O altă posibilitate este folosirea de clienţi sau servere modificate, astfel încât transferul să se realizeze prin canale sigure (de exemplu, folosind SSL - Secure Sockets Layer). Browserele cunosc nativ şi protocolul FTP (schema URL este: ftp://[cont@]server.domeniu/ ). Protocolul este FTP (File Transfer Protocol) şi este specificat în RFC 454. Funcţionează pe modelul client-server.

2.1.1 Server FTP Caracteristici: Importanţa serviciului FTP este indicată şi de faptul că toate sistemele Unix sunt instalate cu un set de programe client şi server.

10

Reţele de calculatoare

Utilizează 2 porturi: portul 21 - pe care se transmit comenzile de la client la server; portul 20 - de pe care serverul iniţiază conexiunea pe care se va face transferul de informaţie. Trebuie verificat dacă există în fişierul /etc/services o intrare care să facă asocierea dintre numele simbolic ftp şi 21, numărul de port TCP cu care este asociat acest serviciu. În fişierul /etc/services trebuie să existe următoarele linii:
ftp ftp-data 21/tcp; 20/tcp.

Când serviciul FTP este pornit de către super-serverul inetd, administratorul trebuie să se asigure că fişierul de configurare a programului inetd (/etc/inetd.conf) conţine o linie de forma:
ftp stream ftpd tcp nowait root /usr/sbin/ftpd

În sistemele Windows, FTP trebuie instalat explicit, fie ca serviciu de reţea, fie ca parte a server-ului Web (IIS - Internet Information Server).

2.1.2 Client FTP Suita programelor care includ clienţi FTP variază de la cele care dezvoltă şi administrează servere WWW (Microsoft FrontPage, Macromedia Dreamweaver) la cele de aplicaţii de birotică (Microsoft Office, existând variante care integrează perfect clientul FTP cu Windows Explorer). Programele "ascund" comenzile clientului ftp din linia de comandă, majoritatea punând accent sporit pe transferul informaţiilor de la client la server, spre deosebire de situaţia clasică, în care transferul majoritar era de la server la client. Clientul – pe staţia utilizatorului, poate fi: comanda ftp - de al prompt-ul DOS; un program sub SO Windows (exp: WinFTP); tasta upload al browser-ului Internet Explorer, folosind schema URL: ftp://user@infocib.ase.ro/cale_HOME/

11

FTP şi poşta electronică

Există mai multe modalităţi de transfer. Vom exemplifica modul din prompt MS-DOS: c:\>ftp >? vă arată toate subcomenzile ftp >o infocib.ase.ro - deschide conexiunea cu server-ul de ftp de pe infocib user: contul_vostru password: parola_voastra >lcd c:\director_local – schimbă directorul de pe maşina locală, acolo unde se găsesc fişierele voastra/ sau unde doriţi să le puneţi pe cele aduse >bin – trecerea modului de transfer din ASCII în binar; se recomandă pentru fişiere ZIP, EXE, imagini etc. >hash – vizualizarea transferului fiecărui 2048 B >cd director_server – schimbă directorul din home directory-ul user-ului >put fis.ext – pune fişierul din directorul local curent pe server-ul infocib, în directorul din home-ul utilizatorului >mput *.ext – multiple put – pune toate fişierele cu extensia .ext, cerând confirmare la fiecare >get fis.ext – ia de pe server şi pune pe local >mget * - multiple get >quit – închidere sesiune 2.2 Serviciul de poştă electronică – e-mail Cunoscut şi sub denumirea de e-mail (electronic mail), este cel care a stat la baza dezvoltării Internet-ului, datorită caracteristicii sale de a permite trimiterea de documente electronice între utilizatorii conectaţi la reţea. Funcţionarea serviciului poate fi considerată asincronă, în sensul că emiţătorul şi receptorul nu trebuie să fie simultan conectaţi pentru ca mesajul să ajungă de la sursă la destinaţie. Principalele componente sunt: 1. agentul utilizator (UA - User Agent), care este de obicei un program cu care utilizatorul îşi citeşte şi trimite poşta electronică; 2. serverul de poştă electronică (cutia poştală), locul în care ajunge poşta electronică şi din care agentul utilizator preia poşta; 12

Reţele de calculatoare

3. agenţii de transfer (MTA - Mail Transfer Agent), care preiau mesajele de la UA şi le retransmit prin reţea către cutia poştală a destinatarului.

Andrei Agent Utilizator (UA)
SMTP

Bogdan

Agent Utilizator (UA) Agent postal (MTA)
POP, IMAP

Agent postal (MTA) SMTP Agent postal (MTA) Cutie postala pentru Andrei Agent postal (MTA) Cutie postala pentru Bogdan

Figura 2.1 Modul de transmisie a poştei electronice şi protocoalele utilizate în cadrul acestui sistem La terminarea compunerii unei scrisori, agentul utilizator o plasează într-o coadă prelucrată de agentul de transfer. Acesta aşteaptă ca în coada sa de intrare să fie plasată o scrisoare, pe care o trimite tuturor destinatarilor. Pentru a trimite scrisoarea unui destinatar, agentul de transfer acţionează ca un client şi contactează serverul maşinii de la distanţă în care se află cutia poştală a destinatarului. Clientul stabileşte o legătură TCP cu serverul şi îi trimite mesajul, în conformitate cu protocolul SMTP (Simple Mail Transport Protocol). Serverul primeşte mesajul şi plasează copia scrisorii în cutia corespunzătoare destinatarului. Programul de transfer este optimizat să trateze împreună toţi recipienţii situaţi într-o aceeaşi maşină distantă. Pentru comunicarea între utilizatorii diferitelor sisteme de poştă electronică s-au introdus porţi de poştă electronică (realizează conversia între formatele de mesaje proprietare şi permit, astfel, transmiterea mesajelor dintr-un sistem în altul). Poşta electronică are facilităţi importante de retransmitere a mesajelor către unul sau mai mulţi destinatari. Programul care realizează retransmiterea 13

FTP şi poşta electronică

foloseşte o bază de date, din care află cum trebuie să prelucreze mesajul. Fiecare intrare în baza de date, numită listă poştală (mailing list) are propria sa adresă poştală şi conţine o mulţime de adrese. La sosirea unei scrisori, programul examinează adresa de destinaţie şi determină dacă aceasta corespunde unei liste poştale. Dacă da, atunci programul retransmite o copie a mesajului către fiecare adresă din listă. Programul de retransmitere consumă resurse importante (memorie şi timp). De aceea el este găzduit de un sistem care oferă aceste resurse, numit poartă poştală (e-mail gateway). Listele păstrate de porţile poştale sunt, de obicei, publice. Mesajele de poştă electronică sunt compuse din trei părţi, primele două fiind descrise în cadrul RFC 822: antet: zonă care cuprinde informaţiile de control ale mesajului (adresele emiţătorului şi receptorilor, data expedierii, traseul mesajului etc.); mesaj: cuprinde mesajul propriu-zis; fişiere ataşate: sunt de regulă binare şi însoţesc mesajul principal. Din punctul de vedere al utilizatorului, cele mai importante câmpuri ale antetului se referă la adresa destinatarului (sau ale destinatarilor). Câmpul to: specifică o listă de adrese de poştă electronică, fiecare destinatar din cei menţionaţi în această listă urmând să primească o copie a mesajului. Câmpul cc: (de la carbon copy, copie la indigo) specifică, de asemenea, o listă de persoane care vor primi copii ale mesajului. Atunci când se doreşte trimiterea mesajului către un destinatar, fără ca receptorii să cunoască acest lucru, se poate folosi câmpul bcc: (blind carbon copy, copie la indigo invizibilă). Adresele de poştă electronică au formatul general utilizator@server_poştă, unde utilizator este numele de cont sau un pseudonim al destinatarului, iar server_poştă este adresa staţiei care face serviciul de cutie poştală sau un nume de domeniu. Protocoale implicate în transferul poştei electronice pe Internet: 1. SMTP (Simple Mail Transport Protocol) – unul dintre cele mai importante protocoale de comunicaţie între MTA-uri, definit în RFC 821. El este folosit atât pentru comunicarea între agenţii de transport al poştei, cât şi pentru transmisia mesajului de la agentul utilizator către serverul local de transmisie a poştei electronice (care, în mod uzual, este acelaşi cu serverul care menţine cutiile poştale). 14

Reţele de calculatoare

2. Post Office Protocol, definit în RFC 1225. Versiunea sa cea mai utilizată se numeşte POP3 – permite descărcarea poştei de pe serverul central, iar modelul de lucru implementat este decuplat (off-line). Presupune existenţa a două cutii poştale, una pentru recepţie (cea de pe server) şi una de lucru (cea gestionată de agentul utilizator). Sincronizarea între cele două cutii poştale nu este prevăzută explicit în cadrul protocolului şi este, practic, imposibil de realizat o menţinere unitară a poştei electronice în cazul în care utilizatorul nu foloseşte întotdeauna acelaşi calculator pentru a-şi accesa poşta. Serverul POP3 lucrează pe maşina pe care se află cutia poştală. Clientul POP3 se execută pe PC-ul utilizatorului. La apelul său, clientul POP3 face identificarea utilizatorului (numeparolă), apoi legătura cu serverul POP3. Acesta accesează cutia poştală a utilizatorului şi transmite clientului noile scrisori aflate aici. POP3 foloseşte tot protocolul TCP, ca şi SMTP, dar este diferit de acesta. Sistemul care păstrează cutia poştală găzduieşte două servere, unul SMTP şi unul POP3. Serverul POP3 poate fi folosit şi cu conexiuni comutate (dial-up). 3. IMAP (Interactive Mail Access Protocol) – definit în RFC 1064, ajuns la versiunea 4. Se foloseşte pentru a se înlătura deficienţele constatate în POP3. Acesta permite ca agentul utilizator să lucreze cu copii temporare ale mesajelor, iar toată gestiunea mesajelor este menţinută pe server. Modul de gestiune folosit de produsele bazate pe IMAP este cuplat (on-line). Această abordare este comodă pentru utilizatorii care nu au un punct fix de lucru, fiind adaptată pentru reţele de tip Intranet. 4. DMSP (Distributed Mail System Protocol) – definit în RFC 1056; presupune existenţa mai multor cutii poştale şi permite transferul scrisorilor către o staţie de lucru, după care se deconectează. După reconectare, scrisorile sunt retransferate şi sistemul este resincronizat.

15

FTP şi poşta electronică

Ambele protocoale au două mari deficienţe: autentificarea se face pe baza unei parole care circulă în clar prin reţea iar mesajele aduse de la server sunt transferate în clar. Servicii de directoare: LDAP (Lightweight Directory Access Protocol) - protocol uşor de acces la cataloage. Serviciul de directoare este folosit, în special, în legătură cu sistemul de poştă electronică deoarece îi furnizează acestuia atât adrese, cât şi certificate necesare pentru criptarea şi semnarea mesajelor de poştă. Se poate construi o agendă cu informaţii despre persoanele implicate în sistemul de poştă, printr-un serviciu centralizat de directoare şi clienţi LDAP (atât Netscape, cât şi Microsoft au adoptat LDAP). Transferul documentelor prin intermediul poştei electronice: Prin facilitatea de ataşare a documentelor la un mesaj de poştă electronică este posibilă transmiterea unui fişier binar, nu numai text, de la emiţător către destinatar. Pentru o transmisie corectă şi o identificare uşoară a tipului documentului ataşat, transferul se face conform standardului MIME. Documentele binare sunt codificate conform standardului BASE64, care specifică transformarea unei secvenţe de 3 caractere pe 8 biţi într-o succesiune de 4 caractere care pot fi tipărite (litere, cifre, semne de punctuaţie), reprezentate pe 6 biţi. Tipul documentului ataşat este indicat în antetul mesajului de poştă electronică, folosindu-se codificarea bazată pe tipurile MIME. Tipul documentului permite programelor de poştă electronică să lanseze în execuţie programul care ştie să vizualizeze documentul ataşat recepţionat. La sistemele Unix, unde se utilizează programul mail pentru trimiterea mesajelor, fişerele se ataşează cu comanda ~r nume_fiş în corpul mesajulul. Implicit SMTP-ul permite transfer de documente ASCII. Cele binare trebuie trimise după ce li s-a aplicat uuencode, iar la recepţie se va face uudecode. Caracteristici MIME: MIME (Multipurpose Internet Mail Extensions) - standard definit pe parcursul a mai multor documente RFC: 1521, 2045, 2046, 2047, 2048 şi 2049. 16

Reţele de calculatoare

Cel mai folosit mod de specificare a tipului de conţinut. Dezvoltat iniţial pentru a permite introducerea în cadrul mesajelor de poştă electronică a unor noi tipuri de informaţii pe lângă cele clasice de tip text. Sistemul MIME a fost preluat şi de Web prin protocolul HTTP. Din acest motiv, tipurile documentelor sunt cunoscute şi sub numele de tipuri MIME. Identificatorul de tip este definit ca fiind compus dintr-un tip şi un subtip, cele două componente fiind separate printr-un slash. Este o completare a RFC 822, introducând alte 5 antete de mesaje: MIME-version, Content-Description, Content-ID, Content-Tranfer-Encoding, Content-Type, precum şi 7 tipuri (text, image, application, message, multiplart etc.) cu mai multe subtipuri. Tipuri/subtipuri MIME Tabel 2.1 Tip/subtip MIME text/plain Tipul informaţiei asociate Informaţie de tip text care nu necesită interpretări speciale text/html Document ce conţine o pagină HTML image/gif Document de tip imagine codificată conform standardului GIF image/jpeg Document de tip imagine codificată conform standardului JPEG application/octet- Fişier binar, cu tip nespecificat, care trebuie tratat ca un stream şir de octeţi video/mpeg Film codificat conform standardului MPEG Pentru transferul mesajelor în siguranţă, există două variante: Criptarea canalului de comunicaţie – se face prin intermediul unui protocol sigur, de tipul SSL (Secure Sockets Layer). Practic, înainte de începerea "discuţiei" dintre agentul utilizatorului şi cutia poştală, se stabileşte un canal criptat pe care se va face atât autentificarea, cât şi transferul mesajelor. Soluţia rezolvă ambele probleme ale sistemelor de poştă. La ora actuală, singurul client de poştă electronică folosit pe scară largă care este capabil să stabilească conexiuni SSL este Netscape Messenger, atunci când accesează o cutie poştală de tip IMAP. 17

FTP şi poşta electronică

Criptarea mesajului - lasă deschisă problema autentificării cu cutia poştală, dar rezolvă atât problema transferului sigur al mesajului, cât şi pe cea a verificării identităţii emiţătorului. De exemplu, soluţia de tip PGP poate fi implementată cu succes în medii Windows şi Unix, asigurând integrare cu toţi clienţii de poştă electronică. Problema autentificării în siguranţă a utilizatorului cu cutia poştală poate fi rezolvată atât prin criptarea canalului de comunicaţie, cât şi prin extensiile aduse celor două protocoale care gestionează poşta electronică de la client. Astfel, protocolul IMAP prezintă un mod opţional de criptare doar pe perioada autentificării, iar firma Microsoft a adus unele extensii protocolului POP3 (mecanismul SPA - Secure POP Authentication) care au fost înglobate în clienţii de mail Outlook şi Outlook Express. Din păcate, aceste soluţii nu au un sprijin important din partea producătorilor de servere de poştă electronică sau din partea producătorilor de clienţi. 2.3 Exerciţii 1. Studiaţi RFC-urile menţionate în seminar (pentru ftp, e-mail, SMTP, POP3, IMAP, MIME) 2. Verificaţi existenţa serverelor de ftp, e-mail, pop3 pe infocib (ps aux) şi portul pe care rulează (netstat –a) 3. Porniţi şi testaţi serverul de ftp din PWS (Personal Web Server), folosind consola de management MMC (se lansează din Internet Service Manager) 4. Creaţi-vă un cont de e-mail pe http://mailcom.ase.ro. Citiţi-vă e-mail-ul folosind un client de e-mail configurat pentru POP3, IMAP, apoi folosiţi un browser. 5. Citiţi-vă poşta de pe infocib folosind un client de e-mail sub SO Windows (folosiţi POP3). 6. Recapitulaţi programul mail din Unix. Trimiteţi prin acest sistem (cu SMTP) un fişier binar (uuencode/ uudecode).

18

3 Servere Web
3.1 Introducere Un server WWW este un program care răspunde pe o conexiune TCP şi furnizează servicii unuia sau mai multor clienţi. Există o mare varietate de servere Web pentru diferite forme de date, ca de exemplu: Apache - pentru platforme Unix, Windows. Conţine negocieri, fişiere log extinse. CERN - pentru platforme Unix, VMS. Conţine instrumente de căutare şi facilităţi de autorizare a accesului. NCSA - pentru platforme Unix; server public. IIS (Internet Information Server) – pentru WinNT Server, XP. PWS (Personal Information Server) – pentru Win.95/NT Workstation. 3.2 IIS Serverul de Web IIS (Internet Information Server) are următoarele caracteristici: Internet Information Server – server de Web pentru SO Windows NT Server, Windows 2000 Server Family. Ajuns la versiunea 5.0, disponibil cu Windows 2000 Server. PWS – Personal Web Server – pentru Win 9x şi NT Workstation, disponibil cu Option Pack 4. Elemente de securitate: Restricţii IP şi de domenii Internet – se poate da/lua accesul la anumite pagini în funcţie de adresa IP sau de domeniul de la care se conectează utilizatorul; 19

Servere Web

Comunicaţii sigure – prin SSL (Secure Socket Layer) şi TSL (Transport Layer Security); SGC (Server-Gated Cryptography) – extensie a SSL, care permite utilizarea de criptări pe 128 biţi; Stocare de certificate de autentificare – integrat cu Windwos CryptoAPI; gestionarea se realizează prin componenta Windows Certificate Manager; Autentificare rezumat (digest authentification) permite autentificarea utilizatorilor prin servere proxy şi ziduri de protecţie; include autentificare Windows pentru accesul la paginile deWeb; Kerberos v5 – protocol de autentificare integrat în Win2000 care permite trecerea elementelor de autentificare printr-o reţea de calculatoare Windows; Fortezza – standard de securitate al guvernului USA; asigură confidenţialitatea, integritatea, autentificarea şi controlul mesajelor, componentelor şi sistemelor; Administrare: crearea de servere virtuale (porturi diferite, IP acelaşi sau diferit) şi directoare virtuale (alias – utile când paginile pe Web se găsesc pe mai multe drive-uri ale calculatorului; sunt reprezentate prin icoana cu glob într-un colţ);

contorizarea proceselor pentru fiecare server de Web care rulează. limitarea % CPU pentru procesele ASP, ISAPI, aplicaţii CGI; setări pentru drepturile de acces: Read, Write, Execute, Script la nivel de site, director sau fişier; administrare la distanţă prin Web; fiecare site suportă şi un Operator, cu drepturi restrânse; administrare centralizată prin MMC (Microsoft Management Console) – include programe numite “snap-ins”; 20

Reţele de calculatoare

protecţia aplicaţiilor – IIS oferă 3 niveluri: • • • Low (IIS Processes) – aplicaţiile rulează în acelaşi process ca şi serviciile Web (Inetinfo.exe) Medium (pooled) - implicit; aplicaţiile rulează într-o altă instanţă a DLLHost.exe; High (Isolated) - aplicaţiile rulează în procese diferite de serviciile Web (DLLHost.exe).

3.3 Exerciţii IIS 1. Verificaţi existenţa IIS: port, director, proces, serviciu; 2. Verificaţi dacă există c:\Inetpub (directorul rădăcină al IIS), respectiv directoarele wwwroot, ftproot pentru serverele de web şi ftp; 3. Verificaţi dacă rulează InetInfo.exe (serverul ca serviciu) (CRTLALT-DEL -> Task Manager -> Processes) (Control Panel-> Services); 4. Lansaţi pagina implicită a IIS (http://localhost/);

21

Servere Web

5. Lansaţi Computer Management; 6. Vizualizaţi setările implicite ale serverului implicit IIS (home directory, port, drepturi etc); 7. Creaţi un site pe portul 8000 cu numele grupei. Daţi drept de browse; puneţi un fişier cu extensia .html în directorul setat ca root pentru documentele serverului. Verificaţi site-ul; 8. Modificati fişierul implicit de pornire în index.html (în consola de management), apoi redenumiţi fişierul dvs. în index.html, după care reîncărcaţi site-ul; 9. Vizualizaţi porturile ocupate (netstat –a –n|more) 10. Din consola de management, creaţi un director virtual cu numele dumneavoastră în site-ul creat anterior şi daţi drept de browse pe acel director (în afară de cele implicite). Refaceţi paşii cu fişierul default; 11. Din Sharing, creaţi un alt director virtual în acelaşi site, după care testaţi-l. Faceţi în aşa fel încât accesul să se realizeze pe bază de cont de Windows cu parolă. 3.4 NCSA Crearea unui server http utilizarea un server deja existent, de exemplu www.infocib.ase.ro crearea propriul server: gata compilat sau sub formă de surse. Caracteristici NCSA: Codul sursă al versiunii httpd_1.3 are şapte directoare: cgi-bin, conf, icons, logs, cgi-src, src, support, dintre care ultimele trei conţin fişiere "makefile", prin care se compilează produsul. Utilizatorul trebuie să modifice anumiţi parametri doar din makefile-ul directorului src. Produsul httpd_3.0 compilat după aplicarea utilitarelor uncompress şi tar se obţin directoarele: 1. BIN cu fişierul httpd. 2. CONFIG cu patru fişiere de configurare. 3. ICONS cu fişiere de tip .gif şi .xbm. 4. CGI-BIN pentru fişier cgi. 5. LOGS pentru a se vedea logările/erorile de logare. 6. HTDOCS pentru fişierele de tip .html.

22

Reţele de calculatoare

Se bazează pe CGI şi utilizează programe de criptare. Există trei tipuri de configurare a serverului: prin compilarea sursei httpd, având de modificat variabile în /src/Makefile şi /src/config.h (la versiunea de la NCSA); modificarea fişierelor de configurare cu parametri specifici sistemului; configurare în timpul rulării. Principalele tipuri de fişiere şi directivele care trebuie configurate sunt: httpd.conf – fişierul de configurare al serverului – conţine informaţii referitoare la: ServerType – tipul serverului (stand-alone sau inetd); ServerRoot – locaţia unde se găseşte daemon-ul; de exemplu: /usr/etc/httpd; ServerName – aliasul DNS, adică numele serverului WWW, sub forma în care este înregistrat. De exemplu www.infocib.ase.ro (orice server nou creat de forma www sau de altă formă trebuie să fie înregistrat pentru a putea fi utilizat şi de alţii); AccessConfiguration şi ResourceConfiguration – calea fizică pe care se găsesc fişierele de configurare pe server; de exemplu: conf/access.conf, conf/srm.conf; Port –indică portul pe care httpd-ul va asculta cererile clienţilor; este o valoare între 0-65536; implicit este 80; srm.conf – fişierul de configurare al resurselor serverului, cum ar fi amplasarea documentelor şi a scripturilor CGI. DocumentRoot - directorul ce conţine fişierele pe care le pune la dispoziţie httpd-ul; exemplu: /usr/etc/httpd/htdocs; UserDirectory – directorul ce specifică un subdirector pe care trebuie sa-l creeze utilizatorii pentru html-urile proprii. Pentru ca userii să poată scrie în acel director trebuie comutat de pe "disable", care este implicit, şi pus pe "enable". Redirect – creează un document virtual pe server; Alias – creează o legătură între un document/director virtual de pe serverul de Web şi un document/director de pe calculatorul server; ScriptAlias – indică directoarele care sunt autorizate să includă script CGI.

23

Servere Web

access.conf - fişierul de configurare al accesului – defineşte politica de limitare a dreptului de acces la diferitele documente ale serverului. Atât în zona sistem, cât şi în home-ul utilizatorilor trebuie să existe directorul Web, unde se depun documentele .html. Utilizatorii îşi creează directorul Web, în cadrul home directorului. Pentru ca ceilalţi utilizatori să aibă acces la acest director, trebuie să i se pună atributele de read şi execute pentru alţii. Accesul la fişiere se va face astfel: http://www.default.server/~username/nume_fişier.html Exemplu de fişier httpd.conf: port 80 User nobody Group #2 ServerAdmina dmin_nume@www.infocib.ase.ro ServerRoot /usr/local/etc/httpd ErrorLog logs/error_log TransferLog logs/httpd.pid ServerName www.infocib.ase.ro DocumentRoot /usr/local/etc/httpd/htdocs UserDir Web DirectoryIndex index.html FancyIndexing on DefaultIcon /icons/unknown.xbm ReadmeName README HeaderName HEADER IndexIgnore */.??* *~ *# */HEADER* */README* AccessFileName .hhtaccess DefaultType text/plain Alias /icons/ /usr/local/etc/httpd/icons Alias /info/ /usr/local/etc/httpd/htdocs/info Alias /document/ /u/pub/document ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin Configurarea accesului pentru directorul htdocs, ce conţine documentaţie: < Directory/usr/local/etc/httpd/htdocs> OptionsIndexes FollowSymLinks Allow Override All * pentru .htaccess files < Limit GET > 24

Reţele de calculatoare

Order Allow, Deny Allow from all < / Limit > < / Directory >

* implicit este Deny

Etapele de instalare a serverului httpd: prin rularea stand-alone – serverul se execută ca un daemon clasic. El aşteaptă sosirea conexiunilor şi serveşte cererile. La fiecare cerere a clientului creează o copie a sa. Este o cale mult mai rapidă (recomandată); din inetd (Internet Daemon) – serverul este administrat printr-un superdaemon care ascultă un port TCP/IP şi se ocupă cu lansarea procesului httpd la fiecare cerere a unui client (inetd-ul facând swap către httpd). Acesta este pornit printr-un fişier de comandă, de exemplu /etc/rc.local şi rulează continuu ca un daemon de "sendmail". Pentru aceasta trebuie introdusă comanda: "/usr/etc/httpd &" în rc.local sau rc; Se poate renunţa la semnul de background "&", dacă fişierul de configurare /etc/httpd.conf se găseşte la locul implicit şi este specificat şi portul pe care trebuie să asculte. Dacă se utilizează modul stand-alone, pe sistemele Unix, doar root-ul poate rula httpd pe porturi mai mici decât 1024, care sunt privilegiate, ceilalţi useri având acces de la 1024 în sus. Un exemplu de formă de rulare a serverului, poate fi: httpd [-d director_iniţial_server] [-f fisier_de_configurare][-v] unde -v este opţiunea pentru afişarea versiunii de server http. Forma generală de lansare a unui server httpd este următoarea: httpd [-opt -opt -opt ...] [director] unde opt poate fi: -r fişier_de_Configurare, cel folosit drept fişier de configurare. În cazul în care nu se pune, implicit se consideră /etc/httpd.conf; -p port, portul de ascultare. Porturile mai mici decât 1024 sunt privilegiate. Fără acest argument se consideră că se rulează ca "inetd" şi utilizează stdin şi stdout drept canale de comunicaţie; -l log_fişier înregistrează cererile de conectare; -restart, restartează un httpd ce deja rulează, reîncărcând fişierele de configurare şi redeschizând fişierul de login (log file); -gc_only, doar pentru opţiunea de "proxy"; -v, verbose – comută pe colectorul de depanare; -vv, very verbose – comută pe mult mai multe mesaje de depanare; 25

Servere Web

-version afişează versiunea de httpd şi libwww (The WWW Common Library); -dy dă posibilitatea vizualizării (navigării) conţinutului directorilor, aceştia devenind nişte documente hipertext. Acestă opţiune se poate seta şi din directiva de configurare DirAccess; -dn nu permite vizualizarea directorilor; o acţiune de încercare a accesului în directori va genera un mesaj de eroare; -ds vizualizare selectivă a directorilor, accesul fiind permis doar pentru cei conţinuţi în fişierul www_browsable; -dt pentru toţi directorii navigabili care conţin un fişier README, incluzând textul fişierului în partea superioară a directorului, înainte de listarea conţinului directorului (se setează directiva de configurare DirReadme); -db, idem, dar pune textul fişierului README în partea inferioară. Aceste două opţiuni pot fi combinate cu -dy, -dys, -dty, etc; -dr dezactivează includerea fişierului README. Exemplu: httpd -r /usr/etc/httpd.conf -p 80 este un server standalone ce rulează pe portul 80, cu fişierul de configurare de mai sus. Dacă se doreşte renunţarea la server atunci se poate folosi: if [-f /usr/etc/httpd]; then (/usr/etc/httpd && (echo -n 'httpd')) & >/dev/console fi Dacă sunt probleme la instalare, se recomandă rularea cu opţiunea -v şi citirea FAQ-ului corespunzător, consultarea documentaţiei referitoare la bug-uri. 3.5 Apache Caracteristici: Versiuni sub SO Unix (/var/apache/) şi SO Windows (c:\Apache\); structură de directoare (asemănătoare cu NCSA). Exemplificaţi pentru Apache sub SO Windows şi sub SO Unix. Fişiere de configurare (asemănătoare cu NCSA). Exemplificaţi pentru Apache sub SO Windows şi sub SO Unix. 26

Reţele de calculatoare

Documentaţie http://www.apache.org/ şi local, după instalare Apache sub SO Windows sau sub SO Unix (infocib.ase.ro:1800). Documentaţi-vă despre directivele care vă permit crearea unor servere virtuale. 3.6 Exerciţii NCSA, Apache 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. Conectaţi-vă pe un server de Unix (exp: infocib.ase.ro) Verificaţi ce servere de Web rulează (NCSA, apache) (ps aux). Unde se găsesc aceste servere? (/usr/local/etc/httpd/; /var/apache/...) Pe ce porturi rulează (netstat –a), ce versiune de software? (httpd –help) Vizualizaţi structura de directoare şi fişierele de configurare pentru fiecare în parte. Care este denumirea directorului pe care trebuie să-l creaţi în Home Directory, pentru a accesa paginile voastre de Web cu serverul de Web NCSA. Dar pentru Apache? Transferaţi pe server fişierele .html. Creaţi în home directory un director Web, în care mutaţi fişierele .html create în seminarul anterior. Daţi dreptul de citire şi execuţie pentru toată lumea directorului Web, cu toate subdirectoarele sale. Accesaţi pagina voastră de Web de pe infocib, utilizând fiecare server de Web instalat. (~cont). Accesaţi o pagină situată în alt subdirector din Web. Studiaţi documentaţia apache sub Unix de pe server. Creaţi un mic script SHELL (pentru a-l pune în zona cgi-bin), care să afişeze de câte ori a fost vizitată pagina voastră (opţional). APACHE sub SO Windows 1. Download kit: ftp://ecomm.ase.ro/ /apache2_0.43-win32-x86no_ssl.msi 2. Documentaţie: --------,,-----------/apachedocs.pdf 3. Instalare: a. alegeţi varianta custom b. pornire manuală pe portul 8080 c. directorul c:\apache\

27

Servere Web

4. Configurare: a. Vizualizati si modificati fişierul httpd.conf, astfel încât home-ul pentru utilizatori să fie: c:\stud_document\ (exp: Alias /users "F:\users" ). b. Ce module sunt încărcate? Cum se pot încărca celelalte? (-V, -l). c. Verificaţi dacă este portul 8080 ocupat. d. Verificaţi dacă programul apache este pornit ca proces sau serviciu. e. Vizualizaţi structura de directori ai serverului apache. Intraţi în directorul bin. f. Verificaţi ce opţiuni aveţi din linie de comandă pentru comanda „apache” (apache -?). g. Verificaţi configuraţia (apache –t). Accesaţi paginile noului server. h. Porniţi serverul apache ca proces din linie de comandă (nu din meniu). i. Testaţi-l pe default, cât şi pentru un alt director. j. Porniţi serverul apache ca serviciu. Verificaţi existenţa serviciului. k. Puneţi în cgi-bin un script care să vă afişeze un contor pe pagina voastră. l. Verificaţi noul server de Web de pe acest port (apache –t; netstat -a). m. Documentaţi-vă în legătură cu porturile unui sistem, care sunt ocupate, pe care le puteţi folosi ca utilizator privilegiat şi ca utilizator obişnuit. n. Creaţi un nou fişier de configurare (alt nume, alt port). Porniţi serverul cu acest fişier nou şi testaţi-l (–f file_name). o. Intraţi cu cont şi parolă pe directorul vostru virtual. i. Editaţi httpd.conf, modificaţi denumirea fişierelor .htaccess, .htpasswd: <Directory "F:\users"> AllowOverride AuthConfig Options None Order allow,deny Allow from all </Directory> ii. Atenţie la aspectele de securitate: <Files ~ "^htaccess"> Order allow,deny 28

Reţele de calculatoare

Deny from all </Files> <Files ~ "^htpasswd"> Order allow,deny Deny from all </Files> iii. Creaţi în directorul vostru fişierul htaccess: AuthType Basic AuthName "Carmen's Area!" AuthUserFile "F:/users/carmen/htpasswd" require user cs iv. Creaţi fişierul de parole în directorul vostru: C:\apache\bin\htpasswd –c htpasswd cs p. Creaţi un server virtual pe aceeaşi adresă IP. Verificaţi-l. (-t –D DUMP_VHOST). (Fişierul hosts trebuie editat). Trebuie pus şi modulul „LoadModule vhost_alias_module modules /mod_vhost_alias.so”? Testaţi noul site (http//nume2:port). NameVirtualHost * <VirtualHost *> DocumentRoot "F:/users/carmen" ServerName carmens2 # Other directives here </VirtualHost> <Directory "F:\users"> AllowOverride AuthConfig Options None Order allow,deny Allow from all </Directory>

29

4 Utilitare TCP/IP
4.1 Utilitare TCP/IP Utilitarele linie de comandă TCP/IP prezintă o mare importanţă, deoarece pot fi folosite atât la depanarea erorilor de configurare, cât şi la aflarea de informaţii referitoare la configuraţia curentă. Utilitare pentru depanarea erorilor de configurare şi testarea conectivităţii Tabel 4.1 Utilitar Descriere Testează conexiunea cu un computer ping Afişează conţinutul cache-ului local în care sunt stocate arp adresele IP asociate adreselor fizice ale plăcilor de reţea (MAC) pentru computerele din LAN Afişează configuraţia TCP/IP curentă ipconfig Afişează statistici şi conexiuni pentru protocolul NetBT nbtstat Afişează statistici şi conexiuni pentru protocolul TCP/IP netstat Afişează sau modifică tabela de rutare locală route hostname Afişează numele computerului Verifică ruta până la un computer aflat la distanţă tracert Verifică dacă routerele de pe drumul până la un computer aflat pathping la distanţă funcţionează corect şi în acelaşi timp detectează pierderile de pachete de date rezultate în urma trecerii prin diferite noduri ale reţelei Toate aceste utilitare sunt executate din linia de comandă. Pentru informaţii referitoare la modul în care se folosesc, cu excepţia hostname şi tracert, deschideţi o fereastră de comandă (Start->Programs->Accessories>Command Prompt), şi tastaţi comanda, urmată de parametrul/?. Dacă informaţiile afişate încap pe mai mult de un ecran şi nu le puteţi urmări, folosiţi parametrul |more. Pentru a folosi utilitarul hostname, trebuie doar să tastaţi numele acestuia şi să apăsaţi tasta Enter. Va fi afişat numele computerului. Pentru informaţii referitoare la modul de folosire a utilitarului tracert, tastaţi numele acestuia şi apăsaţi tasta Enter. 30

Reţele de calculatoare

Utilitare pentru conectarea la distanţă folosind protocolul TCP/IP Utilitar FTP TFTP Telnet RCP RSH REXEC Tabel 4.2 Descriere Facilitează transferul bidirecţional de fişiere între un computer pe care rulează Windows şi un server FTP (de exemplu, Windows 2000 Server). Facilitează transferul bidirecţional de fişiere între un computer pe care rulează Windows şi un server TFTP. Oferă o conexiune la un computer ce suportă protocolul telnet. Sistemele de operare Microsoft nu oferă suport decât pentru clienţi telnet. Copiază fişiere între un computer cu Windows şi unul ce oferă suport pentru RCP (Remote Copy Protocol), de exemplu un computer pe care rulează UNIX. Rulează comenzi pe un computer pe care este instalat UNIX. Rulează un proces pe un computer aflat la distanţă.

Vom descrie în continuare în detaliu o serie de utilitare TCP/IP. Utilitarul ipconfig Ipconfig se foloseşte pentru verificarea configuraţiei protocolului TCP/IP. Pentru afişarea tuturor informaţiilor disponibile, se foloseşte parametrul /all. Rezultatul tastării comenzii ipconfig /all este următorul: Dacă este setată o configuraţie validă, este afişată adresa IP şi masca de subreţea, precum şi gateway-ul implicit, dacă este cazul. Dacă este detectat în reţea un duplicat al adresei IP folosite, va fi afişată adresa IP folosită, dar în dreptul măştii de subreţea se va trece 0.0.0.0. Dacă Windows nu a putut obţine o adresă IP de la un server DHCP, va fi afişată adresa alocată prin tehnologia APIPA. Utilitarul ping Ping este un instrument folosit pentru testarea conexiunii TCP/IP între computerul dumneavoastră şi unul aflat la distanţă. Ping transmite pachetele utilizând ICMP ECHO_REQUEST şi se aşteaptă primirea unui 31

Utilitare TCP/IP

răspuns de confirmare pentru fiecare pachet transmis prin ICMP ECHO_REPLY. Sintaxa comenzii este ping adresa_IP_a_computerului_de_la_distanţă. Utilitarul finger Listează numele de login, numele complet, numele terminalului, precum şi alte caracteristici. Opţiuni - selectiv: Format de redare redus -b -f Suprimă afişarea părţii de antet -i Afişează o listă cu timpii inactivi -l Format de redare extins -q Afişează o listă rapidă de utilizatori Utilitarul netstat Comanda netstat este folosită pentru a extrage o serie de informaţii cum ar fi tabelele de rutare, conecţiile active, fluxuri. Vom prezenta o serie de opţiuni folosite cu această comandă. -a Solicită afişarea stării socketurilor. Cele asociate cu procesele server nu sunt afişate -i Afişează starea interfeţelor ce au fost autoconfigurate -m Afişează modul de utilizare a memoriei -r Afişează tabelele de rutare -p nume_protocol Limitează informaţiile la un protocol anume Utilitarul traceroute Este utilizat pentru a identifica traseul ce trebuie urmat de un pachet pentru a ajunge la destinaţie. Această comandă lucrează utilizând un câmp special TTL (time to live) din cadrul pachetului IP. Utilitarul arp Comanda arp afişează şi modifică tabela de corespondenţă între adrese Internet şi adrese Ethernet (MAC). În momentul în care nu există intrări ARP pentru o anumită adresă Internet se va afişa un mesaj în acest sens. 32

Reţele de calculatoare

Opţiuni: -a -d nume

Afişează toate intrările din tabele ARP curentă Şterge intrările corespunzătoare din tabela ARP -s adresă host Crează o nouă intrare în tabela ARP folosind o adresă Ethernet

4.2 Testarea unei configuraţii TCP/IP Vom prezenta în continuare care sunt paşii ce trebuie urmaţi pentru verificare configuraţiei computerului şi pentru testarea conexiunilor la computere aflate la distanţă, ce implică eventual şi existenţa unor routere. ipconfig Folosiţi utilitarul ipconfig pentru a verifica dacă a fost iniţializată configuraţia TCP/IP. ping 127.0.0.1 Folosiţi utilitarul ping cu adresa internă a plăcii de reţea pentru a verifica dacă protocolul TCP/IP este instalat corect şi placa dumneavoastră de reţea îl foloseşte. ping adresa_IP_a_computerului_dumneavoastră Folosiţi utilitarul Ping cu adresa IP a computerului dumneavoastră pentru a elimina riscul existenţei în reţea a unui duplicat al adresei IP folosite. ping adresa_IP_a_gateway-ului_implicit Folosiţi utilitarul ping cu adresa IP a gateway-ului implicit (aceasta poate fi aflată folosind comanda ipconfig) pentru a verifica dacă gateway-ul implicit este operaţional şi computerul dumneavoastră poate să comunice cu acesta. ping adresa_IP_a_unui_computer_aflat_la_distanţă (pe alt segment de reţea) Folosiţi utilitarul ping cu adresa IP a unui computer aflat pe alt segment de reţea (de exemplu, infocib sau nemesis) pentru a verifica dacă se poate stabili o conexiune cu un computer aflat la distanţă prin intermediul unui router. În general, dacă acest ultim pas reuşeşte, atunci ceilalţi paşi sunt inutili. Totuşi, în cazul în care nu reuşeşte, va trebuie să urmaţi succesiunea de paşi de mai sus pentru a putea localiza problema.

33

Utilitare TCP/IP

4.3 Exemple de folosire a unor utilitare TCP/IP Arp –a – afişează conţinutul cache-ului ARP (adrese IP asociate adreselor fizice ale plăcilor de reţea). Folosiţi mai întâi comanda ping pentru ca Windows să poată stoca adresa fizică (MAC) a plăcii de reţea folosită de computerul aflat la distanţă. Ex: Secvenţa ping ecomm.ase.ro arp -a va duce la afişarea adresei MAC a serverului ecomm. tracert adresa_IP_a_computerului_de_la_distanţă – afişează nodurile de reţea prin care trece un pachet de date până să ajungă la computerul destinaţie. pathping adresa_IP_a_computerului_de_la_distanţă – reprezintă o combinaţie între comenzile tracert şi ping, fiind testată conexiunea cu fiecare nod de reţea (router) până la computerul destinaţie, folosindu-se comanda ping în mod automat pentru fiecare dintre acestea. nbtstat –A adresa_IP_a_computerului_de_la_distanţă – afişează numele NetBIOS al unui computer aflat la distanţă, în cazul în care este cunoscută adresa IP a acestuia. netstat –a – afişează toate conexiunile stabilite în reţea, precum şi toate porturile deschise pe computerul dumneavostră.

34

5 Adresare IP
5.1 Clase de adrese Fiecare familie de protocoale trebuie să conţină un mod de adresare, pentru a identifica reţelele şi nodurile în cadrul acestora. Adresele Internet folosite de IP sunt reprezentate pe 32 de biţi şi sunt alocate în mod unic la nivel global, de o autoritate centrală şi mai multe autorităţi regionale. Adresele pe 32 de biţi sunt specificate de aşa-numita vesiune 4 a IP. Recent a fost standardizată versiunea 6 (IPv6), în care adresele se reprezintă pe 128 octeţi. În vederea unei alocări sistematice, adresele IP au fost divizate în cinci clase de adrese. Dintre acestea trei (clasa A, B, C) vor fi discutate în amănunt. Orice nod conectat într-o reţea TCP/IP trebuie să aibă o adresă IP (ruterele, care dispun de mai multe interfeţe de reţea, vor avea câte o adresă IP pentru fiecare interfaţă). A fost introdusă şi o convenţie de scriere a acestor adrese: fiecare din cei patru octeţi ai adresei este notat distinct prin numărul zecimal corespunzător, cele patru valori fiind separate prin punct, ca în exemplul următor: 123.1.232.11. O altă convenţie de scriere este următoarea: 20.0.0.0/12, ce denotă aplicarea unei măşti de 12 biţi pe adresa 20.0.0.0, adică selectează toate valorile posibile în ultimii 20 biţi de adresă. Analog, 194.110.6.0/26 aplică o mască de 26 biti pe adresa 194.110.6.0/, adică selectează ultimii şase biţi de adresă (64 valori). Recent a fost introdusă şi distincţia între adrese publice şi adrese private. Se numesc adrese publice cele care sunt obţinute de la autorităţile de alocare a adreselor şi sunt rutate în Internet. Aceste adrese au caracter de unicitate, în sensul că nici o adresă nu este multiplu alocată. Datorită creşterii explozive a conectărilor la Internet a apărut preocuparea faţă de epuizarea adreselor pe 32 de biţi şi una din soluţiile adoptate pentru evitarea acestui fenomen a fost să se rezerve câteva adrese care să poată fi utilizate intern (privat) de orice organizaţie, fără a fi vizibile în afara organizaţiei (nu vor fi rutate în afara organizaţiei). Astfel de adrese sunt: 10.0.0.0 - 10.255.255.255 (reţea de clasă A) 172.16.0.0 - 172.16.255.255 (reţea de clasă B) 192.168.0.0 - 192.168.255.255 (bloc de reţele de clasă C) 35

Adresare IP

Rămâne la latitudinea utilizatorului alegerea adreselor private pe care le foloseşte, dar aceasta trebuie făcută conform unor criterii de performanţă. Unul dintre criteriile de alegere este evident dimensiunea reţelei interne: dacă aceasta are doar câteva zeci de calculatoare nu se justifică alegerea adreselor private de clasă B sau A. Sintetizarea noţiunilor referitoare la adresarea IP Tabel 5.1 Denumire Adresa IP Adresă de reţea Descriere Număr pe 32 biţi, scris de obicei în format zecimal, grupat pe cei patru octeţi, prin care se poate identifica în mod unic un nod (interfaţă). Număr pe 32 biţi, scris de obicei în format zecimal, grupat pe cei patru octeţi, care identifică o reţea. Numărul nu poate fi asignat unui nod (interfeţă). Porţiunea din adresă corespunzătoare gazdei conţine numai valori binare de 0. Număr pe 32 biţi scris de obicei în format zecimal grupat pe cei patru octeţi, utilizat pentru a adresa toate nodurile (interfeţele) din cadrul unei reţele de calculatoare. Porţiunea din adresă corespunzătoare gazdei conţine numai valori binare de 1. Număr pe 32 biţi scris de obicei în format zecimal grupat pe cei patru octeţi, utilizat pentru a calcula adresa de reţea prin efectuarea unui şi logic între mască şi o adresă IP.

Adresă de broadcast

Mască de reţea

Prin definiţie, toate nodurile dintr-o reţea posedă aceeaşi valoare numerică pentru porţiunea de reţea din adresele IP. Cealaltă parte a adresei IP se numeşte zonă de gazdă (host). Aceasta diferă de la un nod (interfaţă) la altul. Adresele de clasa A sunt folosite în reţelele cu un număr foarte mare de noduri aflate sub aceeaşi autoritate (companii transnaţionale, organizaţii mondiale, etc.). Adresele de clasă A folosesc opt biţi (un octet) pentru a identifica reţeaua. Prin urmare ceilalţi 24 biţi sunt folosiţi pentru a identifica nodurile (interfeţele). Prin urmare unei reţele de clasă A i se pot asigna 224 noduri. Adresele de clasa B au rezervată o zonă de reţea de 16 biţi, iar cele de clasă C au rezervată o zonă de reţea de 24 biţi.

36

Reţele de calculatoare

Adresele de clasa B au fost atribuite iniţial marilor universităţi şi companii. În ultima vreme obţinerea unei adrese de clasa B este dificilă. Tabelul 2 sintetizează aceste caracteristici. Caracteristici adrese Clasă Număr de octeţi-biţi utilizaţi pentru a identifica reţeaua Număr de octeţi-biţi utilizaţi pentru a identifica interfaţa Tabel 5.2 Numărul de adrese asignabile pe reţea* 24 2 -2 216 - 2 28 - 2

A 1 (8) 3 (24) B 2 (16) 2 (16) C 3 (24) 1 (8) *Există două adrese rezervate pentru fiecare reţea.

Adresele de reţea sunt similare adreselor IP obişnuite însă nu sunt asignabile unei interfeţe anume. La nivel conceptual adresele de reţea referă grupul tuturor adreselor IP dintr-o reţea. De exemplu adresa 7.0.0.0 identifică o reţea de clasă A, 130.9.0.0 identifică o reţea de clasă B, iar 200.4.3.0 identifică o reţea de clasă C. Tabelul 3 sintetizează aspectele referitoare la adresele de reţea. Marje adrese IP Clasă Valoarea primului octet 1 - 126 128 – 191 192 - 223 Adrese de reţea valide Număr de adrese de reţea valide Tabel 5.3 Numărul de adrese asignabile pe reţea 224 - 2 216 - 2 28 - 2

A B C

1.0.0.0 – 126.0.0.0 27 – 2 128.1.0.0 – 214 – 2 191.254.0.0 192.0.1.0 – 221 – 2 223.255.254.0

Există o serie de excepţii care reies şi din tabelul 3. De exemplu, adresa 0.0.0.0 este folosită ca adresă de broadcast, iar adresa 127.0.0.0 este folosită ca adresă de loopback. Alte exemple de adrese rezervate ar fi: 128.0.0.0, 191.255.0.0, 192.0.0.0 şi 223.255.255.0.

37

Adresare IP

O mască de reţea standard este definită ca având valori binare de 0 corespunzător poziţiilor din adresă ce definesc host-ul. În tabelul 4 sunt definite măştile de reţea standard. Măşti de reţea standard Clasă A B C Număr de octeţi-biţi ce identifică reţeaua 1 (8) 2 (16) 3 (24) Tabel 5.4 Masca de reţea standard 255.0.0.0 255.255.0.0 255.255.255.0

În momentul în care se doreşte împărţirea în subreţele se alocă în cadrul adresei IP un număr de biţi care identifică subreţelele. Aceştia sunt preluaţi din cadrul zonei de host a adresei IP. Astfel, în cadrul adresei IP, sunt definite trei zone: reţea, subreţea şi host. Biţii ce identifică reţeaua sunt definiţi prin tipul clasei, cei de host sunt definiţi de către masca de reţea folosită, iar cei de subreţea sunt obţinuţi prin preluarea biţilor rămaşi. De exemplu o mască de reţea de forma: 255.255.255.240, utilizată în cadrul unei reţele de clasă C, determină un număr de patru biţi de host.
8 24-x x

Reţea

Sub-reţea

Host

16

16-x

x

Reţea

Sub-reţea

Host

24

8-x

x

Reţea

Sub-reţea

Host

Figura 5.1 Structurarea unei adrese de IP Putem face o serie de observaţii privitoare la cele discutate: Două adrese IP unice din aceeaşi reţea au valori identice pentru partea de reţea, diferind prin partea de host.

38

Reţele de calculatoare

Două adrese IP unice din aceeaşi subreţea au valori identice în partea de reţea, în cea de subreţea diferind doar prin partea de host. Două adrese IP unice aflate în subreţele diferite dintr-o reţea de clasă A, B sau C au aceeaşi valoare în partea de reţea şi diferă prin partea de subreţea. Dacă nu s-ar utiliza împărţirea în subreţele, cel mai mic grup de hosturi ce s-ar putea forma ar fi echivalent cu o clasă de adrese (A, B sau C în funcţie de caz). Numărul de reţele disponibile ar fi insuficiente. 5.2 Exerciţii rezolvate 1. Având adresa IP 134.141.7.11 şi masca de reţea 255.255.255.0 să se specifice care este adresa care identifică subreţeaua. Adresa este de clasa B; am evidenţiat îngroşat biţii care identifică subreţeaua. Adresa: Masca de reţea: Rezultatul: 134.141.7.11 1000 0110 1000 1101 0000 0111 0000 1011 255.255.255.0 1111 1111 1111 1111 1111 1111 0000 0000 134.141.7.0 1000 0110 1000 1101 0000 0111 0000 0000

2. Având adresa IP 193.193.7.7 şi masca de reţea 255.255.255.0 să se specifice care este numărul care identifică subreţeaua. Ţinând cont că este vorba despre o adresă de clasă C, iar masca este 255.255.255.0, rezultă că nu se utilizează împărţirea în subreţele. Adresa: Masca de reţea: Rezultatul: 193.193.7.7 1100 0001 1100 0001 0000 0111 0000 0111 255.255.255.0 1111 1111 1111 1111 1111 1111 0000 0000 193.193.7.7 1100 0001 1100 0001 0000 0111 0000 0111

3. Având adresa IP 134.141.7.11 şi masca de reţea 255.255.255.0 să se specifice care este adresa de broadcast pentru subreţea.

39

Adresare IP

Adresa: Masca de reţea: Rezultatul: Adresa de broadcast

134.141.7.11

1000 0110 0000 1011 255.255.255.0 1111 1111 0000 0000 134.141.7.0 1000 0110 0000 0000 134.141.7.255 1000 0110 1111 1111

1000 1101 0000 0111 1111 1111 1111 1111 1000 1101 0000 0111 1000 1101 0000 0111

4. Având adresa IP 193.193.7.7 şi masca de reţea 255.255.255.0 să se specifice care sunt adresele IP asignabile în această subreţea. Adresa de subreţea este 193.193.7.0, iar cea de broadcast este 193.193.7.255. Adresele de IP asignabile se găsesc în intervalul 193.193.7.1 - 193.193.7.254. 5. Având adresa IP 140.1.1.1 şi masca de reţea 255.255.255.248 să se specifice care sunt adresele IP asignabile în această subreţea. Adresa de subreţea este 140.1.1.0, iar cea de broadcast este 140.1.1.7. Adresele de IP asignabile se găsesc în intervalul: 140.1.1.1 - 140.1.1.6. 6. Având adresa IP 10.5.118.3 şi masca de reţea 255.255.255.0 să se specifice care sunt subreţelele ce se pot forma. Adresa este de clasă A. Acest lucru implică faptul că octeţii 2 şi 3 sunt în întregime rezervaţi pentru identificarea subreţelelor. S1 S2 S3 S4 S5 S6 Sn 0000 1010 0000 0000 0000 0000 0000 0000 0000 1010 0000 0000 0000 0001 0000 0000 0000 1010 0000 0000 0000 0010 0000 0000 0000 1010 0000 0000 0000 0011 0000 0000 0000 1010 0000 0000 0000 0100 0000 0000 0000 1010 0000 0000 0000 0101 0000 0000 0000 1010 1111 1111 1111 1111 0000 0000 10.0.0.0 10.0.1.0 10.0.2.0 10.0.3.0 10.0.4.0 10.0.5.0 10.255.255.0

7. Să se proiecteze o reţea care să cuprindă trei situri Ethernet legate prin linii seriale. Reţeaua poate creşte până la un număr de maxim 100 de subreţele, fiecare cu maximum 200 noduri. Se va folosi adresa de reţea 40

Reţele de calculatoare

172.16.0.0. Să se determine măştile de subreţea care îndeplinesc criteriile date. Arhitectura este cea prezentată în figură.

Ruterul A

Ruterul B

Ruterul C

Rezolvare Masca trebuie să aibă minim 8 biţi pentru host. Dacă am avea 7 biţi pentru host ar însemna că am putea identifica 27 -2 (126) interfeţe, ceea ce ar fi insuficient pentru a acoperi necesarul de 200 adrese. Numărul de subreţele necesar este 100, ceea ce implică un număr minim de şapte biţi rezervaţi, deoarece 27 este cea mai mică putere a lui doi mai mare decât 100. Primii 16 biţi vor avea valoarea 1, deoarece adresa indicată este de clasă B. În concluzie masca de subreţea va avea următoarea formă:
11111111 11111111 1111111X 00000000
Biţi de reţea Numărul minim de biţi de subreţea Numărul minim de biţi de host

Observăm că rămâne un bit care poate fi asignat atât grupului de biţi ce identifică subreţeaua, cât şi grupului de biţi care identifică hostul. Acest bit a fost marcat cu X. Există două posibilităţi de mască de reţea: 255.255.254.0 sau 255.255.255.0. Vom continua pe primul model, deoarece cel de-al doilea este mai simplu.

41

Adresare IP

Subreţelele ce se pot forma sunt: 172.16.0.0 172.16.2.0 172.16.4.0 ..................... 172.16.252.0 172.16.254.0 Vom selecta primele şase subreţele aşa cum reiese şi din tabelul următor: Subreţea Router A Ethernet Router B Ethernet Router C Ethernet Linie serială A-B Linie serială A-C Linie serială C-B Mască de subreţea 255.255.254.0 255.255.254.0 255.255.254.0 255.255.254.0 255.255.254.0 255.255.254.0 Adresă subreţea 172.16.2.0 172.16.4.0 172.16.6.0 172.16.0.0 172.16.8.0 172.16.10.0 Adresa IP router 172.16.2.1 172.16.4.2 172.16.6.3 172.16.0.1 (A) şi 172.16.0.2 (B) 172.16.8.1 (A) şi 172.16.8.3 (B) 172.16.10.2 (B) şi 172.16.10.3 (C)

Subreţeaua 172.16.2.0/23 Ruterul A

Subreţeaua 172.16.0.0/23

Subreţeaua 172.16.8.0/23

Subreţeaua 172.16.10.0/23

Ruterul B Subreţeaua 172.16.4.0/23

Ruterul C Subreţeaua 172.16.6.0/23

42

6 Comunicaţie client-server la nivel de socket
6.1 Introducere Vom prezenta o serie de aspecte generale: Protocoalele TPC/IP de nivel transport oferă servicii ce permit programelor nivelului aplicaţie să comunice între ele prin intermediul mesajelor. Când o aplicaţie trimite o cerere către nivelul transport pentru a trimite un mesaj, protocolul folosit la acest nivel: • împarte informaţia în pachete; • adaugă un antet de pachet care include adresa destinaţiei; • trimite informaţia nivelului reţea pentru procesare ulterioară. Transmisia şi recepţia datelor se realizează prin intermediul unor porturi de pe server, care identifică destinaţia specifică a mesajului. Nivelul transport este implementat în reţelele TCP/IP prin intermediul a două protocoale: • UDP (User Datagram Protocol) – protocol datagramă utilizator; • TCP (Transmission Control Protocol) – protocol de control al transmisiei. Caracteristici UDP: Asigură servicii de tip datagramă nivelului aplicaţie; Nu este fiabil (nu asigură certitudinea livrării datagramelor, nici mecanismele de protecţie la pierderea sau duplicarea datagramelor); Viteză mare de transmisie; Este un serviciu fără conexiune (emiţătorul nu cunoaşte starea receptorului în momentul transmisiei); Pentru transferul datelor foloseşte nişte entităţi abstracte, numite porturi de protocol, identificate prin numere întregi pozitive şi care au asociate nişte cozi de mesaje prin care se transmit mesajele; Se utilizează pentru mesaje mici (sub 8KB) cu viteză mare; 43

Comunicaţie client-server la nivel de socket

Antetul datagramei UDP conţine: • Source Port Number – adresa portului sursă; • Destination Port Number – adresa portului destinaţie; • Length – lungimea datagramei în bytes; • Checksum – suma de control asociată datagramei (foloseşte acelaşi algoritm ca la protocolul IP). Caracteristici TCP (Transmission Control Protocol): Este fiabil (asigură integritatea datelor transmise, mecanisme de protecţie la pierderea sau duplicarea pachetelor, păstrarea numărului de secvenţă, mecanisme de control al fluxului de date în reţea). Asigură transmisia blocurilor continue de date între porturile de protocol asociate aplicaţiilor. Dimensiunea mesajelor nu este limitată. Viteza de transfer mai mică. SO oferă programelor la nivel aplicaţie o interfaţă comună pentru aceste două protocoale, şi anume interfaţa socket.

6.2 Interfaţa Socket Este o interfaţă între un program de aplicaţie şi serviciul de transport (este un standard de facto), fiind furnizat de o bibliotecă socket sau de sistemul de operare. Se foloseşte conceptul de descriptor, fiecare socket fiind tratat asemănător cu un fişier local. Acest descriptor este transmis aplicaţiei la crearea socket-ului şi apoi este utilizat ca argument în apelurile următoare. Primitive de serviciu Socket API Tabel 6.1
Primitive socket(protofamily, type, protocol) close(socket) bind(socket, localaddr, addrlen) listen(socket,queuesize) newsock = accept(socket, caddress, caddresslen) connect(socket, saddress, saddresslen) Descriere creează un socket închide un socket leagă socket-ul cu un port pune socket în mod pasiv acceptă o cerere de conectare stabileşte legătura cu un server care a făcut accept

44

Reţele de calculatoare Primitive send(socket, data, length, flags) sendto(socket, length, flags, destaddress, addresslen) sendmsg(socket, msgstruct, flags) recv(socket, buffer, length, flags) recvfrom(socket, buffer, length, flags, sndaddr, saddrlen) rcvmsg(socket, msgstruct, flags) Descriere transmite un mesaj transmite un mesaj folosind un socket neconectat primeşte un mesaj primeşte un mesaj pe un socket neconectat

Proprietăţi ale socketurilor în Unix: inovaţie a sistemului Berkeley UNIX; este un punct de comunicaţie prin care un proces poate emite sau recepţiona informaţie sub forma unui flux de bytes; este identificat printr-un descriptor, asemănător cu cel pentru fişier realizează următoarele operaţii elementare: • conectarea la staţia de la distanţă • emiterea datelor • recepţionarea datelor • închiderea unei conexiuni • ataşarea la un port • aşteptarea cererilor de conexiune emise de staţiile de la distanţă • acceptarea cererilor de conexiune la portul local O aplicaţie de reţea include: un program client – care creează un socket pentru a iniţia o conexiune cu o aplicaţie server un program server – care aşteaptă preluarea cererilor clienţilor Structura generală folosită pentru lucrul cu socketuri este: struct sockaddr { unsigned short sa_family; char sa_data[14]; //14 bytes pentru adrese }

45

Comunicaţie client-server la nivel de socket

Membrii structurii sunt: sa_family identifică familia de adrese; sa_data identifică adresa de socket compusă din numărul portului şi adresa IP. Pentru a lucra mai uşor cu structura de mai sus se foloseşte o nouă structură ajutătoare sockaddr_in. Structura sockaddr este una generică (o putem privi ca o clasă abstractă) menită a stoca informaţii de adresă pentru oricare tip de socketuri. Structura ajută la referirea facilă a elementelor adresei de socket: struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct sin_addr; unsigned char sin_zero[8]; // }; Membrii: sin_family corespunde câmpului sa_family din structura sockaddr; sin_port identifică portul; sin_addr identifică adresa IP; sin_zero[8] se iniţializează cu 0. Valorile articolelor sin_port şi sin_addr trebuie să fie în forma big endian. Pentru acest lucru va trebui să se facă conversia între formatul little endian (host order) şi cel big endian (network order). Pentru aceste conversii se vor utiliza funcţiile: htons() – “host to network short” htonl() – “host to network long” ntohs() – “network to host short” ntohl() – “network to host long” O altă funcţie utilă de conversie este inet_addr(), care converteşte adrese IP din forma zecimală grupată în cea de tipul unsigned long în formatul big endian. O altă funcţie ce poate fi folosită în locul celei de mai sus este inet_aton() cu prototipul: int inet_addr(const char *cp, struct in_addr *inp) 46

Reţele de calculatoare

În cazul în care avem o structură in_addr şi dorim să afişăm adresa IP în format little-endian, atunci putem folosi funcţia inet_ntoa(), astfel: printf ("%s", inet_ntoa(ina.sin_addr)); Vom prezenta un exemplu de iniţializare a structurii sockaddr_in: struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); inet_aton( " 2 1 . 3 3 . 2 1 0 . 5 4 " , &(my_addr.sin_addr)); memset(&(my_addr.sin_zero), ' \ 0 ' , 8 ) ; Funcţia socket() crează un socket şi returnează descriptorul de socket (valoare întreagă prin care se identifică un socket) sau –1, în caz de eroare. #include <sys/types.h> #include <sys/socket.h> int socket (int domeniu, int tip, int protocol); Parametrii funcţiei: Domeniul de comunicaţie poate fi setat cu valori de tipul AF_ceva, cum ar fi: AF_UNIX – stabileşte domeniul de comunicare locală UNIX sau AF_INET – utilizat pentru comunicaţii între procese aflate pe aceeaşi maşină sau pe maşini diferite, folosind stiva de protocoale TCP/IP (domeniul Internet). Pentru exemplele curente vom utiliza cea de-a doua variantă. În acest caz, fiecare socket va avea asociată o adresă formată din adresa IP a maşinii gazdă şi un număr de 16 biţi, local gazdei respective, denumit port. Tipul de socket utilizat: SOCK_STREAM (comunicarea se va realiza full-duplex, sigură, orientată-conexiune prin flux de date) sau SOCK_DGRAM (fără conexiune prin datagrame). Se mai poate folosi şi constanta SOCK_RAW care oferă un acces la protocolul reţea (protocolul IP), de nivel inferior. Protocol specifică protocolul particular care va fi utilizat pentru transmisia datelor. Acesta poate fi setat pe “0” pentru ca funcţia să-şi poată alege protocolul corect automat. De exemplu, pentru domeniul AF_INET şi tipul SOCK_STREAM se va considera protocolul de transport TCP, iar pentru cazul în 47

Comunicaţie client-server la nivel de socket

care domain este AF_INET şi tipul SOCK_DGRAM se va considera implicit protocolul de transport UDP. 6.2.1 Comunicaţie client-server TCP/IP În figura 6.1 este prezentat modul de comunicaţie client-server TCP/IP.
getprotobyname ()

socket()

bind()

ge thostbyname()

listen()

ge tprotobyname()

acce pt()

socke t()

stabilire conexiune

conne ct()

read() ce rere write() răspuns close()

write ()

read()

close ()

Figura 6.1 Cient-server TCP/IP Clientul apelează: gethostbyname() pentru a converti numele unui calculator în adresa IP; getprotobyname() pentru a converti numele unui protocol în forma binară folosită de sockets; socket() pentru a crea un socket; connect() pentru a conecta socket-ul la un server; 48

Reţele de calculatoare

recv() (în mod repetat) pentru transferul tuturor datelor de la server (clientul nu are de unde şti dacă serverul transmite datele într-un singur mesaj sau în mai multe); close() pentru a închide socket-ul. Serverul apelează: getprotobyname() pentru a converti numele unui protocol în forma binară folosită de sockets; socket() pentru a crea un socket; bind() pentru a specifica portul local pentru socket; listen() pentru a plasa socket-ul în modul pasiv, apoi în buclă; accept() pentru a accepta o cerere de conectare şi a crea un socket nou pentru această conexiune; send() pentru a trimite date; close() pentru a închide noul socket. Primitivele blocante folosite sunt accept, connect (3 way handshake) şi gethostbyname (conectare cu un server de nume). Primitiva bind() asignează socketul la portul maşinii la care, de exemplu, serverul va asculta cereri de conexiune din partea clienţilor. Prototipul funcţiei este următorul: #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen); Parametri: sockfd este descriptorul de socket my_addr este un pointer la structura ce conţine informaţii referitoare la adresă addrlen poate fi setat la valoarea sizeof(struct sockaddr) Vom prezenta un model de folosire a funcţiei bind(): #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define MYPORT 3490 main() 49

Comunicaţie client-server la nivel de socket

{ int sockfd; struct sockaddr_in my_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; // little endian my_addr.sin_port = htons(MYPORT); // big endian my_addr.sin_addr.s_addr = inet_addr("10.12.110.57"); memset(&(my_addr.sin_zero), '\0', 8); // iniţializare cu 0 a structurii bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)) ; ................. } După ataşarea portului, serverul va trebui să aştepte viitoarele conexiuni de la diverşi clienţi şi să le rezolve cererile. Pentru aceasta se utilizează primitiva listen() urmată apoi de accept(). Primitiva listen() are următoarea formă: int listen(int sockfd, int backlog); Parametri: sockfd este descriptorul de socket; backlog reprezintă numărul maxim de conecţii permise în coada de aşteptare. Primitiva accept() permite acceptarea propriu-zisă a conexiunilor: int accept(int sockd, struct sockaddr *addr, socklen_t *addrlen); Apelul va returna un descriptor de socket corespunzător clientului a cărui conexiune a fost acceptată, stabilindu-se astfel un canal de comunicaţie duplex între server şi client. Acest nou descriptor va putea fi folosit pentru a trimite şi recepţiona date via reţea prin mijlocitori precum send() sau write() şi recv() sau read(). Parametri: sockfd este descriptorul de socket addr va conţine informaţii despre adresa IP şi portul folosite de clientul conectat la server, addrlen stochează lungimea acestei structuri.

50

Reţele de calculatoare

Primitiva send() întoarce numărul de octeţi transmişi, care uneori diferă de numărul de octeţi ce dorim să-i transmitem. Valoarea returnată este numărul de octeţi trimişi în caz de succes. Dacă eşuează, este returnat -l, iar errno descrie eroarea. int send(int sockfd, const void *msg, int len, int flags) Parametri: sockfd este descriptorul de socket msg reprezintă o zonă de memorie în care se află datele ce trebuie trimise len reprezintă lungimea datelor în octeţi flags este de obicei setat pe 0 Primitiva recv() întoarce numărul de octeţi recepţionaţi. Valoarea returnată este numărul de octeţi primiţi în caz de succes. Dacă eşuează, este returnat -l, iar errno descrie eroarea. int recv (int sockfd, void *buf, int len, unsigned int flags); Parametri: sockfd este descriptorul de socket; msg reprezintă o zonă de memorie în care se vor copia datele recepţionate; len reprezintă mărimea acestor date în octeţi; flags este de obicei 0 sau setat la valoarea MSG_PEEK, dacă datele recepţionate trebuie reţinute şi după ce sunt recepţionate; Primitivele close() şi shutdown() Primitiva close() va închide conecţia aferentă descriptorului de socket. Astfel se va bloca orice read() or write() ulterior, cel ce va încerca acest lucru va primi mesaj de eroare. Primitiva shutdown() permite un control superior al procesului de închidere a socketurilor. Funcţia are forma: int shutdown(int sockfd, int opt); Parametri: sockfd este descriptorul pentru socketul ce trebuie închis; opt poate lua valorile: 0 (interzice orice recepţie ulterioară), 1 (interzice orice trimitere ulterioară), 2 (interzice atât recepţia, cât şi trimiterea, similar cu close()) 51

Comunicaţie client-server la nivel de socket

Funcţia întoarce valoarea 0 în caz de success şi valoarea -1 în caz de eroare. 6.2.2 Comunicaţie client-server UDP/IP În figura 6.2 este prezentat modul de comunicaţie client-server UDP/IP.

socket()

socket()

bind()

bind()

cerere recvfrom() sendto()

răspuns sendto() recvfrom()

close()

close()

Figura 6.2 Client-server UDP/IP Mecanismul de lucru este următorul: Se crează un socket care va trata conexiunile cu clienţii. Sunt pregătite structurile de date (sockaddr_in) pentru a ataşa socketul la portul folosit de aplicaţie. Se ataşează socketul la port (bind()). Sunt procesate cererile clientului prin schimbul de mesaje între server şi client (sendto() şi recvfrom()). Pot fi utilizate şi primitivele generale send() şi recv(). Se închide socketul client (close()). Primitiva sento() este folosită pentru trimiterea datagramelor, întoarce numărul de octeţi trimişi şi are următorul prototip: int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

52

Reţele de calculatoare

Parametrii funcţiei: sockfd este descriptorul de socket; msg reprezintă o zonă de memorie în care se află datele ce trebuie trimise; flags va fi iniţializat cu 0 len reprezintă lungimea datelor ce vor fi trimise; to reprezintă un pointer la o structură de tip sockaddr şi conţine adresa de IP şi portul destinaţiei; tolen va fi iniţializat cu valoarea sizeof(struct sockaddr). Primitiva recfrom() este folosită pentru recepţionarea datagramelor, întoarce numărul de octeţi recepţionaţi şi are următorul prototip: int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); Parametrii funcţiei: sockfd este descriptorul de socket; msg reprezintă o zonă de memorie în care se află datele ce sunt primite; flags va fi iniţializat cu 0; len reprezintă lungimea datelor primite; from reprezintă un pointer la o structură de tip sockaddr şi conţine adresa de IP şi portul sursei; fromlen va fi iniţializat cu valoarea sizeof(struct sockaddr) 6.3 Exemplificări 1. Să se construiască un server şi un client TCP/IP. În exemplu, serverul va păstra evidenţa numărului de clienţi care au accesat resursa şi va raporta acest număr la fiecare apel. /* SERVER TCP */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <netdb.h> 53

Comunicaţie client-server la nivel de socket

main(int argc, char ** argv) { unsigned short port; /* portul client */ char buffer[32]; struct sockaddr_in client, server; /*adresele client, server*/ struct hostent * srvinfo; int s, rc, namelen, ns; if(argc!= 2) { printf("Apel: %s port \n", argv[0]); exit(1); } /*preia numele calculatorului local */ if(gethostname(buffer, 32)) perror("Eroare la preluarea numelui serverului"); printf("Nume server: %s \n", buffer); /*preia informatiile despre configurarea hostului*/ if (!(srvinfo=gethostbyname(buffer))) perror("Eroare la preluarea informatiilor despre server"); port=(unsigned short) atoi(argv[1]); /*Creeaza un socket*/ if ((s=socket(AF_INET, SOCK_STREAM, 0)) <0) { perror("Eroare la creare socket"); exit(3); } /*Asociază socketului o adresă de server */ memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* adresa Internet locala */ if ( bind ( s, &server, sizeof(server)) <0) { perror("Eroare la obţinerea adresei"); exit(4); } 54

Reţele de calculatoare

/*Creează coadă pentru cererile de conexiune; va prelua maxim 5 cereri de conexiune de la clienţi, restul fiind refuzate */ if (listen(s, 5) != 0) { perror("Eroare la obţinerea cozii de cereri"); exit(5); } /* Creează un descriptor de socket pentru. comunicaţia serverclient */ namelen = sizeof(client); if ((ns = accept( s, &client, &namelen)) == -1) { perror("Eroare la acceptarea conexiunii"); exit(6); } /* Recepţionează mesajul de la client */ if(recv(ns, buffer, 32, 0) == -1) { perror ("Eroare la recepţie"); exit(7); } /* Afişează mesajul primit de la client */ printf("Mesaj recepţionat de la client, pe TCP: %s\n", buffer); /*Trasmite confirmarea clientului */ if (send(ns, buffer, strlen(buffer), 0) <0) { perror("Eroare la transmisie"); exit(8); } endhostent(); /* închide sesiunea TCP/IP */ close(ns); close(s); exit(0); } 55

Comunicaţie client-server la nivel de socket

/* CLIENT TCP */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <netdb.h> main (int argc, char ** argv) { unsigned short port; /* portul client, acelaşi ca cel specificat în modulul server */ char buffer[32]; struct sockaddr_in server; /*adresă server*/ struct hostent * hostnm; /*informaţii server */ int s, rc; if (argc != 3) { printf("Apel: %s hostname port \n", argv[0]); exit(1); } /*preia numele calculatorului local */ if (!(hostnm=(struct hostent *) gethostbyname(argv[1]))) { perror("Eroare la preluarea numelui serverului"); exit(3); } printf("A preluat numele de server.... \n"); port = (unsigned short)atoi(argv[2]); strcpy(buffer, "Mesaj transferat prin socket, pe TCP"); /*preia informaţiile despre server*/ server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* aceeaşi ca la server */ 56

Reţele de calculatoare

printf("A preluat inf. despre server....\n"); if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("Eroare la creare socket"); exit(4); } printf("A creat socket-ul....\n"); if (connect(s, &server, sizeof(server)) < 0) { perror("Eroare la obţinerea conexiunii"); exit(5); } printf("A realizat conexiunea.....\n"); /* Transmite mesajul serverului */ if (send(s, buffer, strlen(buffer), 0) < 0) { perror("Eroare la transmisie"); exit(6); } printf("A transmis mesajul.....\n"); /* Confirmare de la server */ if (recv(s, buffer, 32, 0) < 0) { perror("Eroare la recepţie"); exit(7); } printf("Confirmarea de la server a fost făcută.... \n"); close(s); exit(0); } 57

Comunicaţie client-server la nivel de socket

2. Să se construiască o aplicaţie server şi una client care să comunice prin datagrame. /* Modul SERVER UDP */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <errno.h> #include <netdb.h> main() { char buffer[32]; struct sockaddr_in client, server; /*adresele client, server*/ int s, rc, namelen; /*Creează un socket*/ if ((s=socket(AF_INET, SOCK_DGRAM, 0)) <0) { perror("Eroare la creare socket"); exit(1); } printf("A creat socket-ul....\n"); /*Asociază socketului o adresă de server */ memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = 0; /* orice port */ server.sin_addr.s_addr = INADDR_ANY; if ( bind( s, &server, sizeof(server)) <0) { perror("Eroare la obţinerea adresei"); exit(2); } printf("S-a alocat o adresă .....\n"); /* Determină portul asignat*/ namelen = sizeof(server); if (getsockname(s, (struct sockaddr *) &server, &namelen)) 58

Reţele de calculatoare

{ perror("Eroare la determinarea portului"); exit(3); } printf("\n Portul asignat este: %d\n", ntohs(server.sin_port)); namelen = sizeof(client); /* Recepţioneaza mesajul de la client */ if (recvfrom ( s, buffer, 32, 0, &client, sizeof(client)) < 0) { perror ("Eroare la recepţie"); exit(4); } printf("A recepţionat mesajul de la client.... \n"); /* Afişează mesajul primit de la client */ printf("\n Mesajul recepţionat de la client este: %s\n", buffer); printf("Parametrii: \n Nume domeniu: %s \n \Port: %d \n Adresa \n", (client.sin_family == AF_INET? \Internet: %s "AF_INET":"AF_UNIX"), ntohs(client.sin_port), inet_ntoa(client.sin_addr)); endhostent (); /* închide sesiunea UDP/IP */ close(s); exit(0); } /* Modul CLIENT UDP */ /* Modul CLIENT UDP */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <netdb.h> main(int argc, char ** argv) { 59

Comunicaţie client-server la nivel de socket

unsigned short port; /* portul client, acelaşi ca cel specificat în modulul server */ char buffer[32]; struct sockaddr_in server; /*adresă server*/ int s, rc; if(argc!= 2) { printf("Apel: %s port \n", argv[0]); exit(1); } port=(unsigned short) atoi(argv[1]); strcpy(buffer, "Mesaj transferat prin socket, pe UDP"); /*preia informaţiile despre server*/ server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* aceeasi ca la server */ if ((s=socket(AF_INET, SOCK_DGRAM, 0)) <0) { perror("Eroare la creare socket"); exit(2); } /* Transmite mesajul serverului */ if(sendto(s, buffer, strlen(buffer)+1, 0, &server, sizeof(server)) < 0) { perror ("Eroare la transmisie"); exit(3); } close(s); exit(0); } 60

Reţele de calculatoare

3. Să se construiască o aplicaţie de tip server stream (TCP) concurent, care aşteaptă un număr N de la un client şi returnează lista numerelor prime mai mici decât N. Rezolvarea servirii concurente a mai multor clienţi se va face folosind apelul fork(). Se crează astfel un proces copil care va servi un anumit client. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <error.h> #include <string.h> #include <stdlib.h> #include <signal.h> /* portul folosit */ const int PORT_SERVER = 9001; /* numarul maxim de clienţi acceptaţi */ const int CLIENTI_MAXIM = 10; extern int errno; /* eroarea returnată */ int ds; /* descriptor pentru server */ int dc; /* descriptor pentru client */ int nr = 0; /* numărul de clienţi */ void semnal (int nr_semnal) /* funcţia de tratare a semnalelor */ { if (nr_semnal == SIGCHLD) { wait (NULL); nr--; /* am pierdut un client */ return; } } /* întoarce 0 dacă nu e prim, i altfel */ int e_prim (int i) { int k; 61

Comunicaţie client-server la nivel de socket

for (k = 2; k * k <= i; k++) if ((i%k) == 0) return 0; return 1; } void client () /* funcţia de tratare a clientului */ { char buffer[100]; char aux[100]; int i,t; int numar, k; sprintf (aux,"Eşti clientul numărul: %d\n",nr); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); /* eroare, am ieşit */ exit (errno); } sprintf (aux, "Daţi numărul:"); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); exit (errno); } bzero (buffer, 100); /* citeşte numarul sub forma de şir de caractere */ if (read (dc, buffer, 100) == 0) { shutdown (dc, 2); exit (errno); } /* din şir de caractere în întreg */ număr = atoi (buffer); for (k = 2; k < număr; k++) if (e_prim (k)) { sprintf (aux, "Număr prim: %d\n", k); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); exit (errno); } 62

Reţele de calculatoare

} shutdown (dc, 2); exit (errno); } /* programul principal */ int main () { struct sockaddr_in server; /* tratăm semnalele */ if (signal (SIGCHLD, semnal) == SIG_ERR) { perror ("signal()") ; exit (errno); } if (signal (SIGPIPE, SIG_IGN) == SIG_ERR) { perror ("signal()"); exit (errno); } /* creăm socket-ul */ if ((ds = socket (AF_INET, SOCK_STREAM, 0)) == -1) { perror ("socket() ") ; return errno; } /* pregătim structurile de date */ bzero (&server, sizeof (server)); server.sin_family = AF_INET; server.sin_port = htons (PORT_SERVER); server.sin.addr.s_addr = htonl (INADDR_ANY); /* ataşăm la port */ if (bind (ds, &server, sizeof (server)) == -1) { perror ("bind()"); return errno; } if (listen (ds, 5) == -1) { perror ("listen() ") ; return errno; } 63

Comunicaţie client-server la nivel de socket

printf ("Aşteptăm clienţi la portul %d...\n", PORT_SERVER) ; while (1) { /* acceptăm un client */ dc = accept (ds, NULL, NULL); /* am ajuns la numărul maxim de clienţi? */ if (nr == CLIENTI_MAXIM) { shutdown (dc, 2) ; continue; } /* lansăm un proces care tratează cererile clientului */ switch (fork ()) { case 0: client (); case -1: perror ("fork()"); break; default: break; } nr++; /* a mai venit un client */ } }

64

7 Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE
Aplicaţiile economice vehiculează un volum mare de date care trebuie prelucrate în vedere obţinerii de informaţii necesare pentru fundamentarea procesului decizional. Globalizarea la nivel microeconomic a activităţii a transformat treptat modelul de prelucare client-server specific primelor aplicaţii de reţea, într-un model bazat pe niveluri de servicii, cel mai simplu incluzând nivelul de acces la date, nivelul logicii aplicaţiei şi nivelul de prezentare prin care aplicaţia este accesată de către utilizatori. .NET este soluţia propusă de Microsoft pentru programarea aplicaţiilor distribuite în Internet, fiind identificată prin următoarele trei componente esenţiale: un mediu de execuţie independent de limbaj optimizat pentru prelucrări distribuite — .NET Framework; un mediu de dezvoltare care oferă suport pentru mai multe limbaje de programare standardizate sau proprietate Microsoft — Visual Studio .NET; sistemul de operare care oferă suport pentru aplicaţiile distribuite dezvoltate pe platforma .NET Framework — Windows Server. Viziunea care a stat la baza iniţiativei .NET a avut în vedere asigurarea următoarelor deziderate: programarea independentă de limbaj; robusteţea şi scalabilitatea aplicaţiilor pe ansamblu; securitatea integrată; uşurinţa implementării; distribuirea prelucrărilor; suportul pentru standarde deschise; mentenabilitatea; facilităţi de depanare avansate. .NET este similară platformei J2EE; ambele constituie o abordare structurată pentru crearea aplicaţiilor distribuite, oferind limbaje compilate în cod intermediar împreună cu o bogată colecţie de interfeţe de programare pentru dezvoltarea aplicaţiilor. Intenţia platformei Java a fost să ofere suport pentru aplicaţiile scrise în limbajul Java şi compilate în cod de octeţi Java. Chiar dacă au existat încercări de a porta şi alte limbaje pe platforma JVM, ele au rămas doar în sfera limbajelor formale, Jython fiind doar un exemplu 65

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

didactic de portare a limbajului de scripting Python pe JVM, şi asta pentru că ideea platformei Java a fost mereu una simplă şi eficientă: un singur limbaj care să ruleze pe mai multe sisteme de operare. Spre deosebire de J2EE, platforma .NET oferă suport pentru mai multe limbaje de programare compilate în Microsoft Intermediate Language (MSIL), plecând de la ideea: o singură platformă pe care pot rula mai multe limbaje. Firma Sun Microsystems a dezvoltat Java atât ca limbaj, cât şi platformă pentru dezvoltarea aplicaţiilor distribuite, existând în prezent trei ediţii ale platformei Java: J2SE (Java 2 Standard Edition), pentru programarea de platformă şi în reţea; J2EE (Java 2 Enterprise Edition), pentru aplicaţii de întreprindere; J2ME (Java 2 Micro Edition), pentru dispozitive mobile. Spre deosebire de .NET, J2EE este un set de specificaţii standardizate şi nu un produs, permiţând dezvoltatorilor să creeze aplicaţii distribuite pe mai multe niveluri. Diferenţele fundamentale între J2EE şi .NET se concretizează în: suportul pentru sisteme de operare; suportul pentru limbajele de programare; metoda de execuţie. Încă de la început Java a fost proiectată să lucreze cu un număr mare de sisteme de operare, rulând în prezent pe platforme: Windows, UNIX, Linux, MacOS, BeOS. Spre deosebire de J2EE, .NET a fost gândită să ruleze doar pe Windows, existând însă încercări de portare a mediului de execuţie şi pe Linux, proiectele de tip Open Source, precum Mono şi Rotor oferind suport pentru majoritatea interfeţelor de programare din .NET. Pentru implementarea aplicaţiilor distribuite este nevoie de servere de aplicaţii pentru publicarea componentelor care înglobează logica aplicaţiei. Paltforma .NET oferă IIS cu ASP.NET prin intermediul căruia se pot publica şi executa servicii Web scrise în limbaje compilabile pe CRL (Common Language Runtime) în MSIL (Microsoft Intermediate Language), cum sunt C#, J#, C++ Managed, Pascal (Delphi), Visual Basic .NET, Perl etc., sau chiar Java prin IkVm şi Mono; Platforma J2EE dispune atât de implementări comerciale, precum WebLogic de la BEA, WebSphere Application Server de la IBM, iPlanet şi SunONE Application Server de la Sun, Enterprise 66

Reţele de calculatoare

Server de la Borland etc., precum şi de implementări Open Source cum sunt JBoss sau JOnAs. Acestea sunt servere de componente EJB (Enterprise Java Beans), care, pentru a putea găzdui servicii Web, necesită, ca şi IIS-ul, un mediu de procesare a mesajelor SOAP şi de gestiune a componentelor de serviciu. În J2EE există mai multe implementări SOAP, precum Axis şi SOAP de la Apache, Web Services Developement Kit (WSDK) de la Sun şi omonimul său de la IBM, sau Glue, iniţial dezvoltată de The Mind Electric, actualmente oferită de WebMethods. Pentru accesul la date, aplicaţiile distribuite fac apel la servere de baze de date relaţionale, prin interfeţe de programare specifice. Platform .NET oferă ActiveX Database Objects .NET (ADO.NET), prin intermediul căreia se poate conecta la server Microsoft precum SQL Server 2000 (sau Yukon în curând), MSDE, Access, dar şi la Oracle Database Server, IBM DB2, precum şi la MySQL sau PostGre SQL. Platforma J2EE dispune de Java Database Connectivity (JDBC), o interfaţă de programare pentru care există drivere de conectare la aproape orice bază de date relaţională sau sistem de fişiere, incluzând Oracle Database Server, IBM DB2, Sybase, MS SQL Server 2000, MSDE, MS Access, MySQL, PostGre SQL etc. Pentru clienţi Web este nevoie de servere Web cu suport dedicat tehnologiilor specifice, astfel: Platforma .NET oferă ASP.NET, o tehnologie dezvoltată din ASP în sensul separării procesărilor pe server de formatarea HTML a rezultatului, permiţând o mai bună încapsulare a codului în executabile binare interpretabile pe CLR. Necesită IIS cu modul ISAPI ASPNET.dll sau Apache cu modul dedicat ASP.NET. Platforma J2EE oferă două tehnologii: servlet şi JSP, cărora li s-a adăugat recent JSF (Java Server Faces), o tehnologie echivalentă cu ASP.NET. Se execută atât pe servere Web, cele mai folosite fiind Tomcat, Orion sau Jetty, cât şi pe servere de aplicaţii J2EE amintite la nivelul logicii aplicaţiei.

67

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

7.1 Nivelul de acces la date 7.1.1 Apelarea procedurilor stocate pe SQL Server Microsoft SQL Server 2000 reduce vizibil timpul necesar pentru a construi soluţii bazate pe Web, de afaceri şi de depozitare a datelor, automatizând în acelaşi timp sarcinile de gestionare şi adaptare. SQL Server 2000 este optimizat pentru a fi folosit cu Windows 2000 şi este proiectat pentru a creşte o dată cu afacerea dumneavoastră. Caracteristicile pentru a aduce pe Web aplicaţiile noi şi existente sunt incluse cu suport XML şi acces HTTP. Alte caracteristici includ capacitatea de căutare de text în bazele de date şi formate de documente cunoscute; auto-gestionare şi adaptare dinamică, servicii de analiză integrate şi migrarea şi transformarea simplificată a datelor. Procedurile stocate sunt o colecţie de declaraţii precompilate stocate sub un nume şi procesate ca o unitate. Procedurile stocate sunt disponibile pentru administrarea SQL Server şi afişarea informaţiilor despre baze de date şi utilizatori. Procedurile stocate instalate o dată cu SQL Server se numesc proceduri stocate de sistem. Când se creează o aplicaţie cu SQL Server, limbajul de programare Transact-SQL (TSQL) este interfaţa primară de programare între aplicaţie şi baza de date SQL Server. Manipularea şi execuţia procedurilor stocate se poate realiza în două moduri: prin stocarea locală a programelor şi crearea aplicaţiilor care să trimită comezile către SQL Server şi să proceseze rezultatele; prin stocarea programelor ca proceduri stocate în SQL Server şi crearea aplicaţiilor care să execute aceste proceduri şi să proceseze rezultatele. Procedurile stocate din SQL Server sunt similare procedurilor din alte limbaje deoarece pot să: primească parametri introduşi şi să returneze valori multiple sub forma parametrilor de ieşire; conţină declaraţii care să îndeplinească operaţiuni în baza de date, inclusiv să cheme alte proceduri. Se poate folosi declaraţia EXECUTE pentru a rula o procedură stocată. Procedurile stocate sunt diferite de funcţii deoarece nu pot returna valori în locul numelui lor şi nu pot fi folosite direct într-o expresie. Avantajele folosirii procedurilor stocate în SQL Server în locul programelor Transact-SQL stocate local în sistemele client sunt: permit programarea modulară: procedura poate fi creată doar o singură dată, stocată în baza de date şi chemată ori de câte ori este nevoie în program. Procedurile stocate pot fi create de o persoană 68

Reţele de calculatoare

specializată în programarea bazelor de date şi pot fi modificate independent de codul sursă al programului care le foloseşte; permit rularea mai rapidă: dacă operaţiunea cere o cantitate mare de cod Transact-SQL sau este rulat în mod repetat, procedurile stocate pot fi mai rapide decât codul Transact-SQL de la client. Ele sunt analizate şi optimizate în momentul creării lor şi versiunea in-memory a procedurii poate fi folosită după ce este executată pentru prima dată; permit reducerea traficului pe reţea: o operaţiune care cere sute de linii de cod Transact-SQL poate fi executată printr-o singură declaraţie care execută codul în cadrul unei proceduri, decât să se trimită sute de linii de cod pe reţea. Pentru apelarea unei proceduri stocate, clientul ADO.NET pentru SQL Server oferă obiectul SqlCommand pentru care se setează proprietatea CommandType la valoarea StoredProcedure, respectiv CommandText ca fiind numele procedurii stocate din spaţiul rolului conexiunii deschise, astfel:
this.sqlCommand = new SqlCommand(); this.sqlCommand.CommandText = "dbo.[getProducts]"; this.sqlCommand.CommandType = CommandType.StoredProcedure; this.sqlCommand.Connection = this.sqlConnection; this.sqlCommand.Parameters.Add(new SqlParameter("@RETURN_VALUE", SqlDbType.Int, 4, ParameterDirection.ReturnValue, false, ((byte)(0)), ((byte)(0)), "", DataRowVersion.Current, null));

în cazul unei proceduri stocate care selectează date din mai multe tabele prin intermediul unui adapter trebuie mapate colecţiile extrase din bază peste tabelele DataSet-ului destinaţie:
this.sqlDataAdapter.SelectCommand = this.sqlCommand; this.sqlDataAdapter.TableMappings.Add("data", "Categories"); this.sqlDataAdapter.TableMappings.Add("data1", "Producers"); this.sqlDataAdapter.TableMappings.Add("data2", "Products"); this.sqlDataAdapter.TableMappings.Add("data3", "Stock");

procedura stocată selectează datele astfel:
CREATE AS SELECT SELECT SELECT SELECT RETURN PROCEDURE dbo.getProducts * * * * FROM FROM FROM FROM Categories; Producers; Products; Stock;

69

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

apelul selecţiei datelor cu ajutorul adapter-ului presupune denumirea tabelei origine ale cărei mapări duc datele în tabele ale DataSet-ului:
DataSet dataSet = new DataSet(); this.sqlDataAdapter.Fill(dataSet, "data");

JDBC oferă obiectul CallableStatement prin intermediul căruia se pot apela proceduri stocate. Obiecte Java
package tutorials.database.storedprocedure; import java.io.Serializable; public class Group implements Serializable { public int GroupId; public String Name; public short Version; } package tutorials.database.storedprocedure; import java.io.Serializable; public class Student implements Serializable { public int StudentId; public String FirstName; public String LastName; public short Version; }

Accesor
package tutorials.database.storedprocedure; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; public class DataAccessor { private Connection connection; public void open(String host, int port, String database, String user, String password) throws SQLException, ClassNotFoundException { Class.ForName("com.microsoft.jdbc.sqlserver.SQLServerDri ver"); this.connection = DriverManager.getConnection(

70

Reţele de calculatoare "jdbc:microsoft:sqlserver://" + host + ":" + port + ";DatabaseName=" + database + ";User="+ user + ";Password=" + password + ";");

} public void close() throws SQLException { this.connection.close(); } public Group[] getGroups() throws SQLException { Vector vector = new Vector(); CallableStatement statement = this.connection.prepareCall("call GetGroups()"); ResultSet results = statement.executeQuery(); while(results != null && results.next()) { Group group = new Group(); group.GroupId = results.getInt(1); group.Name = results.getString(2); group.Version = results.getShort(3); } return (Group[]) vector.toArray(); } public Student[] getStudentsByGroup(int groupId) throws SQLException { CallableStatement statement = this.connection.prepareCall("call GetStudentsByGroup(?)"); statement.setInt(1, groupId); Vector vector = new Vector(); ResultSet results = statement.executeQuery(); while(results != null && results.next()) { Student student = new Student(); student.StudentId = results.getInt(1); student.FirstName = results.getString(2); student.LastName = results.getString(3); student.Version = results.getShort(4); vector.add(student); } return (Student[]) vector.toArray(); } }

7.1.2 Virtualizarea accesului la baza de date Platforma .NET permite accesul la baze de date prin interfaţa ADO.NET, oferind mecanisme de acces bazate pe conexiune activă sau deconectate. În privinţa suportului nativ pentru conectarea la diferite servere, platforma .NET oferă suport pentru SQL Server chiar de la versiunea 1.0 căruia i s-a 71

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

adăugat suportul pentru Oracle în versiunea 1.1, restul serverelor fiind suportate prin intermediul provider-ilor oferiţi de diferite organizaţii. Spre exemplu, pentru accesul la MySQL există mai mulţi provider-i comerciali cât şi Open Source, cel mai cunoscut fiind ByteFX. Dacă în cazul punţii JDBC diferă doar protocolul de conectare în funcţie de server, restul metodelor fiind comune, pe platforma .NET clasele de acces la date se găsesc în pachete diferite şi au tipuri diferite, ceea ce face imposibilă legarea directă la metodele acestora. Prin intermediul signaturii comune a metodelor interfeţei ADO.NET pe care fiecare clasă de acces o implementează, este totuşi posibilă definirea unei interfeţe de acces la date, ce urmează a avea implementări specifice fiecărui provider, implementări care fac apel la pachetele şi clasele provider-ului respectiv. Pentru ca aceeaşi aplicaţie să se poată conecta la mai multe servere de baze de date este necesară virtualizarea accesului la baza de date prin implementarea unui mecanism de fabrică de obiecte care să asigure legarea implementării specifice bazei de date utilizate. se defineşte o interfaţă peste ADO.NET care reuneşte funcţii pentru operaţiile cu baza de date; este necesară definirea unei interfeţe deoarece clasele oferite de către provider-ii ADO.NET au signaturi de pachete diferite, ceea ce face imposibilă instanţierea lor pentru acelaşi tip de bază:
namespace Tutorials.Database { internal interface IDatabaseConnection { void Open(string host, string database, string user, string password); System.Data.DataSet ExecuteQuery(string statement, string table); object ExecuteScalar(string statement); int ExecuteNonQuery(string statement); void Close(); string Provider { get; } string Database { get; } } }

72

Reţele de calculatoare

se implementează interfaţa pentru fiecare server de baze de date utilizând clasele provider-ului ADO.NET specific: Clasă de acces la SQL Server 2000
namespace Tutorials.Database { internal class SQLServerDatabaseConnection: IDatabaseConnection { private System.Data.SqlClient.SqlConnection connection; private string database; public SQLServerDatabaseConnection() { } public void Open(string host, string database, string user, string password) { this.connection = new System.Data.SqlClient.SqlConnection("data source = " + host + "; database = " + database + "; user id = " + user + "; password = " + password); this.connection.Open(); } public System.Data.DataSet ExecuteQuery(string statement, string table) { System.Data.DataSet dataSet = new System.Data.DataSet(); new System.Data.SqlClient.SqlDataAdapter(statement, this.connection).Fill(dataSet, table); return dataSet; } public object ExecuteScalar(string statement) { return new System.Data.SqlClient.SqlCommand(statement, this.connection).ExecuteScalar(); } public int ExecuteNonQuery(string statement) { return new System.Data.SqlClient.SqlCommand(statement, this.connection).ExecuteNonQuery(); } public void Close()

73

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE {

if(this.connection!=null) this.connection.Close();

}

}

} public string Provider { get { return "SQLServer"; } } public string Database { get { return this.database; } }

Clasă de acces la Oracle
namespace Tutorials.Database { internal class OracleDatabaseConnection: IDatabaseConnection { private System.Data.OracleClient.OracleConnection connection; private string database; public OracleDatabaseConnection() { } public void Open(string host, string database, string user, string password) { this.connection = new System.Data.OracleClient.OracleConnection("data source = " + host + "; database = " + database + "; user id = " + user + "; password = " + password); this.connection.Open(); } public System.Data.DataSet ExecuteQuery(string statement, string table) { System.Data.DataSet dataSet=new System.Data.DataSet();

74

Reţele de calculatoare new System.Data.OracleClient.OracleDataAdapter(statement, this.connection).Fill(dataSet, table); return dataSet; } public object ExecuteScalar(string statement) { return new System.Data.OracleClient.OracleCommand(statement, this.connection).ExecuteScalar(); } public int ExecuteNonQuery(string statement) { return new System.Data.OracleClient.OracleCommand(statement, this.connection).ExecuteNonQuery(); } public void Close() { if(this.connection!=null) this.connection.Close(); } public string Provider { get { return "Oracle"; } } public string Database { get { return this.database; } } } }

Clasă de access la MySQL
namespace Tutorials.Database { internal class MySQLDatabaseConnection: IDatabaseConnection { private ByteFX.Data.MySqlClient.MySqlConnection connection; private string database;

75

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE public MySQLDatabaseConnection() { } public void Open(string host, string database, string user, string password) { this.database = database; this.connection = new ByteFX.Data.MySqlClient.MySqlConnection(" data source = "+host+";database = "+database+";user id = "+user+";password = "+password); this.connection.Open(); } public System.Data.DataSet ExecuteQuery(string statement,string table) { System.Data.DataSet dataSet=new System.Data.DataSet(); new ByteFX.Data.MySqlClient.MySqlDataAdapter(statement,this.connec tion).Fill(dataSet, table); return dataSet; } public object ExecuteScalar(string statement) { return new ByteFX.Data.MySqlClient.MySqlCommand(statement, this.connection).ExecuteScalar(); } public int ExecuteNonQuery(string statement) { return new ByteFX.Data.MySqlClient.MySqlCommand(statement, this.connection).ExecuteNonQuery(); } public void Close() { if(this.connection != null) this.connection.Close(); } public string Provider { get { return "MySQL"; } } public string Database { get

76

Reţele de calculatoare { } }

return this.database;

}

}

se construieşte o clasă fabrică de obiecte care instanţiază implementarea interfeţei de acces la baza de date specifică unui anumit server: Clasă fabrică de conexiune la o anumită bază de date
using System; namespace Tutorials.Database { public enum Providers{Oracle, SqlServer, MySql} public class DatabaseConnection { private IDatabaseConnection databaseConnection = null; public void Open(Providers provider, string host, string database, string user, string password) { switch(provider) { case Providers.Oracle: this.databaseConnection = new OracleDatabaseConnection(); break; case Providers.SqlServer: this.databaseConnection = new SQLServerDatabaseConnection(); break; case Providers.MySql: this.databaseConnection = new MySQLDatabaseConnection(); default: this.databaseConnection = null; break; } if(this.databaseConnection != null) this.databaseConnection.Open(host, database, user, password); } public System.Data.DataSet ExecuteQuery(string statement, string table) {

77

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE return this.databaseConnection != null ? this.databaseConnection.ExecuteQuery(statement, table) : null; } public object ExecuteScalar(string statement) { return this.databaseConnection != null ? this.databaseConnection.ExecuteScalar(statement) : null; } public int ExecuteNonQuery(string statement) { return this.databaseConnection != null ? this.databaseConnection.ExecuteNonQuery(statement) : -1; } public void Close() { if(this.databaseConnection != null) { this.databaseConnection.Close(); this.databaseConnection = null; } } public string Provider { get { return this.databaseConnection != null ? this.databaseConnection.Provider : null; } } public bool IsOpened { get { return this.databaseConnection != null; } } } }

Spre deosebire de soluţia ADO.NET în care fiecare provider oferă drivere având signaturi de pachet diferite şi deci incompatibile ca tip de dată, JDBC oferă o interfaţă unitară de acces, ceea ce facilitează implementarea unei clase unice de acces la diferite baze de date. Totuşi, crearea unei conexiuni este specifică fiecărui provider prin driverul şi protocolul de acces aferente, ceea ce impune definirea unei clase abstracte având o singură metodă abstractă care creează o conexiune la baza de date, restul metodelor apelând interfaţa JDBC. 78

Reţele de calculatoare

se defineşte o clasă abstractă care va conţine metoda abstractă de conectare şi implementarea comună a metodelor de acces la date, de forma:
public abstract class DatabaseConnection { protected String host; protected int port; protected String database; protected String user; protected String password; protected java.sql.Connection connection; public abstract void connect(String host, int port, String database, String user, String password) throws java.lang.ClassNotFoundException, java.sql.SQLException; public void close()throws java.sql.SQLException { this.connection.close(); } public java.sql.ResultSet executeQuery(String statement) throws java.sql.SQLException { return(this.connection.createStatement()).executeQuery(s tatement); } public boolean executeInsert(String statement) throws java.sql.SQLException { return(this.connection.createStatement()).execute(statem ent); } public boolean executeUpdate(String statement) throws java.sql.SQLException { return(this.connection.createStatement()).execute(statem ent); } public boolean executeDelete(String statement) throws java.sql.SQLException { return(this.connection.createStatement()).execute(statem ent); } }

pentru conectarea la un anumit server se extinde clasa abstractă prin implementarea metodei de conectare; spre exemplu, pentru conectarea la MySQL, clasa derivată va arăta astfel:
public class MySQLDatabaseConnection extends DatabaseConnection { public MySQLDatabaseConnection() { }

79

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE public void connect(String host, int port, String database, String user, String password) trows java.lang.ClassNotFoundException, java.sql.SQLException { this.host = host; this.port = port; this.database = database; this.user = user; this.password = password; Class.forName("org.gjt.mm.mysql.Driver"); this.connection = java.sql.DriverManager.getConnection("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database + "?user=" + this.user + "&password=" + this.password); } }

pentru conectarea la SQL Server clasa derivată va arăta astfel:
public class SQLServerDatabaseConnection extends DatabaseConnection { public SQLServerDatabaseConnection() { } public void connect(String host, int port, String database, String user, String password) throws java.lang.ClassNotFoundException,java.sql.SQLException { this.host = host; this.port = port; this.database = database; this.user = user; this.password = password; Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDri ver"); this.connection = java.sql.DriverManager.getConnection("jdbc:microsoft:sqlserver ://" + this.host+ ":" + this.port + ";DatabaseName=" + this.database + ";User=" + this.user + ";Password=" + this.password + ";"); } }

în ambele cazuri metoda de conectare face apel la clasele punţii JDBC pentru serverul de baze de date respectiv, astfel încât pentru deschiderea conexiunii prin JDBC este necesară plasarea claselor de acces în CLASSPATH. 80

Reţele de calculatoare

7.2 Nivelul logicii aplicaţiei 7.2.1 Apelarea procedurilor la distanţă Publicarea şi apelarea unui obiect prin .NET Remoting presupune următoarele acţiuni: se defineşte interfaţa şi obiectele de serviciu într-un assembly partajat între server şi client, de forma: Obiect de serviciu
using System; namespace Tutorials.Remoting.Common { [Serializable] public class Customer { public string FirstName; public string LastName; public DateTime DateOfBirth; } }

Interfaţă serviciu
namespace Tutorials.Remoting.Common { public interface ICustomerManager { Customer[] GetCustomers(); } }

se construieşte un proiect în care se implementează interfaţa de apel:
using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using Tutorials.Remoting.Common; namespace Tutorials.Remoting.Service { public class CustomerManager : MarshalByRefObject, ICustomerManager {

81

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE public CustomerManager() { Console.WriteLine("CustomerManager.constructor: Object created"); } public Customer[] GetCustomers() { Customer[] customers = new Customer[2]; customers[0] = new Customer(); customers[0].FirstName = "Iulian"; customers[0].LastName = "Nemedi"; customers[0].DateOfBirth = new DateTime(1979, 7, 24); customers[1] = new Customer(); customers[1].FirstName = "Dan"; customers[1].LastName = "Cuculescu"; customers[1].DateOfBirth = new DateTime(1979, 1, 1); return customers; } } }

pentru publicarea serviciului se poate opta pentru un context Web pe IIS, un serviciu de platformă sau o aplicaţiei consolă de test:
using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using Tutorials.Remoting.Service; namespace Tutorials.Remoting.Server { class Server { [STAThread] static void Main(string[] args) { HttpChannel channel = new HttpChannel(1979); ChannelServices.RegisterChannel(channel); RemotingConfiguration.RegisterWellKnownServiceType( typeof(CustomerManager), "CustomerManager.soap", WellKnownObjectMode.Singleton); Console.ReadLine(); }

82

Reţele de calculatoare }

}

clientul obţine o referinţă la obiectul la distanţă apelând activatorul canalului HTTP la serverul de obiecte, prin intermediul cărei apelează metodele obiectului:
using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels.Http; using System.Runtime.Remoting.Channels; using Tutorials.Remoting.Common; namespace Tutorials.Remoting.Client { class Client { [STAThread] static void Main(string[] args) { HttpChannel channel = new HttpChannel(); ChannelServices.RegisterChannel(channel); ICustomerManager manager = (ICustomerManager) Activator.GetObject( typeof(ICustomerManager), "http://localhost:1979/CustomerManager.soap"); Console.WriteLine("Client.Main(): Reference to CustomerManager acquired"); Customer[] customers = manager.GetCustomers(); foreach(Customer customer in customers) Console.WriteLine("Customer:\n" + "First Name:\t" + customer.FirstName + "\n" + "Last Name:\t" + customer.LastName + "\n" + "Day of Birth:\t" + customer.DateOfBirth.ToString("dd\\.MM\\.yyyy") + "\n"); } } }

83

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

Arhitectura Java pentru apelarea procedurilor la distanţă prin RMI (Remote Method Invocation): Interfaţă de metode apelabile la distanţă
package tutorials.remoting; import java.rmi.Remote; import java.rmi.RemoteException; public interface IPrimeNumbers extends Remote { public int[] getPrimeNumbers(int n) throws RemoteException; }

Implementarea interfeţei de metode apelabile la distanţă
package tutorials.remoting; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class PrimeNumbers extends UnicastRemoteObject implements IPrimeNumbers { public PrimeNumbers() throws RemoteException { super(); } public int[] getPrimeNumbers(int n) throws RemoteException { boolean[] isNotPrime = new boolean[n + 1]; int found = 0; for(int i = 2; i <= n - 1; i++) if(isNotPrime[i] == false) { found++; for(int j = 2; j * i <= n; j++) isNotPrime[j * i] = true; } int[] numbers = new int[found]; int k = 0; for(int i = 2; i <= n; i++) if(isNotPrime[i] == false) numbers[k++] = i; return numbers; } }

84

Reţele de calculatoare

Server pentru obiectul ale cărui metode sunt apelabile la distanţă
package tutorials.remoting; import java.rmi.Naming; import java.rmi.RMISecurityManager; public class Server { public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { PrimeNumbers primeNumbers = new PrimeNumbers(); Naming.rebind("//remoting/PrimeNumbersServer", primeNumbers); } catch(Exception exception) { System.out.println(exception.toString()); } } }

Client care apelează metode ale unui obiect la distanţă
package tutorials.remoting; import java.rmi.Naming; public class Client { public static void main(String[] args) { try { PrimeNumbers primeNumbers = (PrimeNumbers) Naming.lookup("rmi://remoting/PrimeNumbersService"); int n = args.length == 1 ? Integer.parseInt(args[0]) : 1000; int[] numbers = primeNumbers.getPrimeNumbers(n); String message = ""; for(int i = 0; i < numbers.length; i++) message += (message.length() > 0 ? ", " : "") + numbers[i]; System.out.println(message); } catch(Exception exception) { System.out.println(exception.toString()); } } }

85

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

7.2.2 Serializarea tipurilor de date complexe pentru transportul tipurilor de date complexe este necesară serializarea / deserializarea lor XML; mecanismul poate fi implementat declarativ prin intermediul atributelor sau imperativ prin instrucţiuni care apelează un obiect de tipul XmlWriter, respectiv XmlReader: Clasă C# serializată XML în mod declarativ
using System; using System.Xml.Serialization; namespace Tutorials.ComplexTypeServices.Service { [XmlRoot(Namespace = "http://aris.ase.ro/schemas")] public class Contact { [XmlElement("FirstName")] public string FirstName; [XmlElement("LastName")] public string LastName; [XmlElement("Email")] public string Email; } }

Clasă Java serializată XML în mod declarativ
package tutorials.services.complextype; import java.io.Serializable; public class Contact implements Serializable { public String FirstName; public String LastName; public String Email; }

serviciul expune o metodă care întoarce un vector de obiecte serializate XML: Serviciu C#
using System; using System.Collections; using System.ComponentModel;

86

Reţele de calculatoare using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace Tutorials.ComplexTypeServices.Service { [WebService(Namespace = "http://aris.ase.ro/schemas")] public class ContactService : System.Web.Services.WebService { public ContactService() { InitializeComponent(); } #region Component Designer generated code private IContainer components = null; private void InitializeComponent() { } protected override void Dispose( bool disposing ) { if(disposing && components != null) { components.Dispose(); } base.Dispose(disposing); } #endregion [WebMethod] public Contact[] GetContacts() { Contact[] contacts = new Contact[2]; contacts[0] = new Contact(); contacts[0].FirstName = "Iulian"; contacts[0].LastName = "Ilie-Nemedi"; contacts[0].Email = "iulian.nemedi@ase.ro"; contacts[1] = new Contact(); contacts[1].FirstName = "Radu"; contacts[1].LastName = "Constantinescu"; contacts[1].Email = "radu.constantinescu@ase.ro"; return contacts; } } }

într-un proiect Java dezvoltat cu ajutorul mediului Eclipse, se copiază structura unei aplicaţii Glue generate cu ajutorul utilitarului NewApp (copiată de fapt din Glue/app-template); se 87

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

precizează că binarele aplicaţiei vor fi depuse în calea WEBINF/classes; se organizează clasele într-un director sursă, respectiv într-un pachet Java în care se defineşte un tip complex care va fi întors de metodele serviciului Web; pentru a putea fi serializat XML acesta trebuie să implementeze interfaţa java.io.Serializable; se defineşte interfaţa serviciului Web: Interfaţa serviciului Java
package tutorials.services.complextype; public interface IContactService { public Contact[] getContacts(); }

se implementează interfaţa prin intermediul clasei serviciului; în producţie metodele serviciului fac apel la o bază de date pentru extragerea informaţiilor: Serviciu Java
package tutorials.services.complextype; public class ContactService implements IContactService { public Contact[] getContacts() { Contact[] contacts = new Contact[2]; contacts[0] = new Contact(); contacts[0].FirstName = "Iulian"; contacts[0].LastName = "Ilie-Nemedi"; contacts[0].Email = "iulian.nemedi@ase.ro"; contacts[1] = new Contact(); contacts[1].FirstName = "Radu"; contacts[1].LastName = "Constantinescu"; contacts[1].Email = "radu.constantinescu@ase.ro"; return contacts; } }

clientul .NET apelează serviciul prin intermediul unui proxy care conţine clase pentru deserializarea obiectelor complexe pe baza schemei XSD extrasă din descriptorul WSDL al serviciului: Client C#
using System; namespace Tutorials.ComplexTypeServices.ClientForNetService

88

Reţele de calculatoare {

class Client { [STAThread] static void Main(string[] args) { ContactProxy.Contact[] contacts = new ContactProxy.ContactService().GetContacts(); for(int i = 0; i < contacts.Length; i++) Console.WriteLine("Contact:\n" + "\tFirst Name: " + contacts[i].FirstName + "\n" + "\tLast Name: " + contacts[i].LastName + "\n" + "\tEmail: " + contacts[i].Email + "\n"); } } }

clientul Java are nevoie de o clasă pentru reprezentarea obiectului complex deserializat; pentru construirea acesteia platforma Glue Professional oferă utilitarul schema2java; apelarea din Java presupune importarea pachetelui cu definirea tipului de date complex şi a interfeţei serviciu; clasa proxy se obţine prin apelul metodei statice electric.revistry.Registry.bind: Client Java
package tutorials.services.complextype; import electric.registry.Registry; import electric.registry.RegistryException; public class Client { public static void main(String[] args) throws RegistryException { IContactService proxy = (IContactService) Registry.bind(args[0], IContactService.class); Contact[] contacts = proxy.getContacts(); for(int i = 0; i < contacts.length; i++) System.out.println("Contact:\n" + "\tFirst Name: " + contacts[i].FirstName + "\n" + "\tLast Name: " + contacts[i].LastName + "\n" +

89

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE "\tEmail: " + contacts[i].Email + "\n");

} }

existenţa unor tipuri de date elementare echivalente face posibilă serializarea pe o platformă şi deserializarea pe alta a tipurilor de date complexe; chiar şi în absenţa mecanismelor de serializare / deserializare ale containerelor de servicii Web, portabilitatea unui singur tip elementar, de exemplu String, permite traversarea platformei de către un obiect complex, în ultimă instanţă programatorul putând folosi serializarea şi deserializarea String a obiectelor; 7.2.3 Apelarea serviciilor Web în mod asincron Utilitarul wsdl.exe generează metode pentru apelarea serviciului atât în mod sincron, cât asincron. Pentru apelarea asincronă se generează câte o pereche de metode Begin_Apel_Metodă şi End_Apel_Metodă. Apelarea asincronă a unui serviciu Web presupune iniţierea apelului prin execuţia metodei Begin care înregistrează o funcţie delegat callback ce va fi apelată la obţinerea răspunsului de la metoda serviciului. presupunem un serviciu Web a cărui execuţie poate dura un timp mai îndelungat, având o metodă care determină toate numerele prime până la un număr dat ca parametru: Serviciu C#
using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace Tutorials.AsyncCallService.Service { [WebService(Namespace = "http://aris.ase.ro/schemas")] public class PrimeNumbersService : System.Web.Services.WebService { public PrimeNumbersService() { InitializeComponent(); }

90

Reţele de calculatoare #region Component Designer generated code private IContainer components = null; private void InitializeComponent() { } protected override void Dispose( bool disposing ) { if(disposing && components != null) { components.Dispose(); } base.Dispose(disposing); } #endregion [WebMethod] public int[] GetPrimeNumbers(int n) { bool[] isNotPrime = new bool[n + 1]; for(int i = 2; i <= n - 1; i++) if(isNotPrime[i] == false) for(int j = 2; j * i <= n; j++) isNotPrime[j * i] = true; ArrayList numbers = new ArrayList(); for(int i = 2; i <= n; i++) if(isNotPrime[i] == false) numbers.Add(i); return (int[]) numbers.ToArray(typeof(int)); } } }

Interfaţa serviciului Java
package tutorials.services.asynccall; public interface IPrimeNumbersService { public int[] getPrimeNumbers(int n); }

se implementează interfaţa printr-o clasă serviciu: Serviciu Java
package tutorials.services.asynccall; public class PrimeNumbersService implements IPrimeNumbersService { public int[] getPrimeNumbers(int n) { boolean[] isNotPrime = new boolean[n + 1]; int found = 0;

91

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE for(int i = 2; i <= n - 1; i++) if(isNotPrime[i] == false) { found++; for(int j = 2; j * i <= n; j++) isNotPrime[j * i] = true; } int[] numbers = new int[found]; int k = 0; for(int i = 2; i <= n; i++) if(isNotPrime[i] == false) numbers[k++] = i; return numbers;

}

}

se publică serviciul pe un context Glue prin JMS (Java Messaging Services): Aplicaţie gazdă pentru serviciu Java
package tutorials.services.asynccall; import electric.registry.Registry; import electric.registry.RegistryException; import electric.registry.Registry; import electric.server.jms.JMS; public class AsyncServer { public static void main(String[] arguments) throws Exception { JMS.startup("jms:///AsyncCallService"); Registry.publish("PrimeNumbersService", new PrimeNumbersService()); } }

clientul .NET conţine o metodă care va fi apelată în mod asincron la primirea rezultatelor apelului către metoda serviciului Web: Metoda clientului C#
public void LoadComplete(IAsyncResult result) { this.Cursor = Cursors.Default; this.numbers = this.service.EndGetPrimeNumbers(result); string message = ""; for(int i = 0; i < this.numbers.Length; i++) message += (message.Length > 0 ? ", " : "") +

92

Reţele de calculatoare this.numbers[i].ToString(); Console.WriteLine(message); }

apelul sincron al metodei serviciului este înlocuit de apelul asincron al componentei Begin corespunzătoare acesteia:
this.service.BeginGetPrimeNumbers(n, new AsyncCallback(this.LoadComplete), null);

spre deosebire de implementarea .NET în care clientul apela altă metodă a clasei proxy, pe platforma Glue Professional clientul apelează serviciul asincron prin intermediul aceleaşi interfeţe ca şi pentru apelurile sincrone, utilizând însă alt URL pentru serviciu, ceea ce face ca cererile să fie tratate asincron prin JMS: Client Java
package tutorials.services.asynccall; import electric.registry.Registry; import electric.registry.RegistryException; public class Client { public static void main(String[] args) throws RegistryException { String url = "jms://AsyncCallService/PrimeNumbersService.wsdl"; IPrimeNumbersService proxy = (IPrimeNumbersService) Registry.bind(url, IPrimeNumbersService.class); int n = args.length == 1 ? Integer.parseInt(args[0]) : 1000; int[] numbers = proxy.getPrimeNumbers(n); String message = ""; for(int i = 0; i < numbers.length; i++) message += (message.length() > 0 ? ", " : "") + numbers[i]; System.out.println(message); } }

93

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

7.2.4 Publicarea unei componente ca serviciu Web Componentele COM+ sunt implicit apelabile la distanţă deoarece clasa MarshalByRefObject. Publicarea unei componente ServicedComponent ca serviciu pe IIS presupune următoarele acţiuni: se scrie o componentă de serviciu, spre exemplu care necesită accesul tranzacţional la o bază de date pentru a înregistra o comandă; tipurile de date şi interfaţa de apel de la distanţă trebuie organizate într-o bibliotecă referită atât de serviciu care implementează interfaţa, cât şi de clientul care face apelul către serviciu: extind Obiectul tranzacţiei
using System.Xml.Serialization; namespace Tutorials.ServicedComponents.Common { [XmlRoot("Order", Namespace = "http://aris.ase.ro/schemas")] public class Order { [XmlElement("Product", typeof(string))] public string Product; [XmlElement("Quantity", typeof(int))] public int Quentity; } }

Interfaţa de apel
namespace Tutorials.ServicedComponents.Common { public interface IDeliveryService { bool PlaceOrder(Order order); } }

se implementează interfaţa de aplel prin intermediul unei componente de serviciu gestionată tranzacţional în COM+: Componentă de serviciu
using System; using System.EnterpriseServices;

94

Reţele de calculatoare namespace Tutorials.ServicedComponents { [Transaction(TransactionOption.Required)] [JustInTimeActivation(true)] public class DeliveryService : ServicedComponent, Common.IDeliveryService { #region IDeliveryService Members [AutoComplete] public bool PlaceOrder(Common.Order order) { return DateTime.Now.Ticks % 2 == 0; } #endregion } }

se creează o aplicaţie Web pe IIS în care se publică binarele componentei SC împreună cu un descripor Web.config de forma: Descriptor Web
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" type="Tutorials.ServicedComponents.DeliveryService,Tutorials.S ervicedComponents" objectUri="/ServicedComponents/DeliveryService.SOAP"/> </service> </application> </system.runtime.remoting> </configuration>

-

descriptorul Web configurează în cadrul aplicaţiei un serviciu monocanal SOAP, precizând tipul clasei serviciu, assembly-ul în care se găseşte şi adresa la care va răspunde. clientul înregistrează un canal HTTP, obţine de la activator o referinţă locală a obiectului la distanţă, prin intermediul căreia va putea apela metodele interfeţei serviciului:

95

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

Client pentru componeta de serviciu
using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; namespace Tutorials.ServicedComponents.Client { class Client { [STAThread] static void Main(string[] args) { try { HttpChannel channel = new HttpChannel(); ChannelServices.RegisterChannel(channel); Common.IDeliveryService service = (Common.IDeliveryService) Activator.GetObject(typeof(Common.IDeliveryService), "http://localhost/ServicedComponents/DeliveryService.SOAP"); Common.Order order = new Common.Order(); order.Product = "A Product"; order.Quentity = 1; Console.WriteLine(service.PlaceOrder(order) ? "Your order has been placed." : "Your order has been rejected."); } catch(Exception exception) { Console.WriteLine(exception.ToString()); } } } }

Componentele EJB găzduite de containere EJB ale serverelor de aplicaţii Java Enterprise sunt apelabile prin Remote Method Invocation (RMI). Pentru a putea apela o componentă EJB prin intermediul protocolului SOAP, platformele Java de servicii Web interceptează mesajele SOAP/HTTP ale clientului pe care le rutează conform descriptorilor de publicare către un anumit serviciu. Serviciile de tip EJB sunt găzduite de un 96

Reţele de calculatoare

procesor care gestionează starea acestora, mapează metoda apelului SOAP peste metoda corespunzătoare a interfeţei Remote a componentei EJB pe care o apelează apoi prin RMI. De fapt, un serviciu Web de tip EJB nu este altceva decât un client Java pentru componenta EJB găzduit pe serverul de aplicaţii care este apelat prin SOAP de către clienţii externi. pentru o componentă EJB publicată în JBoss pe contextul ejb/Exchange se creează o aplicaţie Glue folosind utilitarul NewApp care de fapt copiază conţinutul directorului apptemplate într-un director cu numele aplicaţiei; descriptorul aplicaţiei Web, fişierul web.xml, aflat în subdirectorul de resurse WEB-INF, conţine maparea servlet-urilor contextului curent, printre care se remarcă servlet-ul glue-SOAP, responsabil cu rutarea mesajelor SOAP către procesorul serviciului:
<servlet> <servlet-name>glue-SOAP</servlet-name> <servletclass>electric.server.http.ServletServer</servlet-class> <init-param> <param-name>httpRegistryRoot</param-name> <param-value>/</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> de asemenea, tot în fişierul web.xml este configurat şi procesorul de servicii SOAPServletContext; în subdirectorul services din WEB-INF se creează câte un

descriptor XML pentru fiecare serviciu găzduit de aplicaţia curentă, având drept model fişierul sample.xml; în cazul publicării unei componente EJB ca serviciu Web fişierul descriptor are următoare formă:
<?xml version='1.0'?> <service> <constructor> <class>electric.service.ejb.StatelessSessionBeanService</class > <args> <contextFactory>org.jnp.interfaces.NamingContextFactory</conte xtFactory>

97

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE <url>jnp://localhost:1099</url> <jndiName>ejb/Exchange</jndiName> <homeInterfaceName>tutorials.ejbstaff.interfaces.ExchangeHome< /homeInterfaceName> </args> </constructor> </service>

descriptorul precizează tipul de Bean publicat, contextul JNDI al componentei EJB pe serverul de aplicaţii şi interfaţa Remote de apel; se construieşte arhiva aplicaţiei Web folosind utilitarul jar cu comanda:
jar cf nume_arhivă.war director_aplicaţie

se publică prin copiere în zona de publicare a serverului JBoss (server/default/deploy) pentru apelarea dintr-un client Java este necesară includerea unei interfeţe similare interfeţei Remote a componentei EJB: Interfaţă de apel la client
package tutorials.ejbstaff.client; public interface IExchange { public double getRate(String county1, String country2); }

Client Java
package tutorials.ejbstaff.client; import electric.registry.Registry; public class Client { public static void main(String[] args) { try { String url = args[0]; IExchange exchange = (IExchange) Registry.bind(url, IExchange.class); double rate = exchange.getRate("usa", "japan"); System.out.println("usa/japan exchange rate = " + rate); } catch(Exception exception) { System.out.println(exception.toString()); } } }

98

Reţele de calculatoare

pentru apelarea dintr-un client .NET se construieşte o clasă proxy prin adăugarea unei referinţe Web la descriptorul WSDL al serviciului; platforma Glue găzduită în JBoss livrează descriptorul WSDL la adresa:
http://server:port/nume_aplicaţie/services/nume_serviciu.wsdl unde numele aplicaţiei este numele fişierului arhivă .war copiat în spaţiul de publicare JBoss, iar numele serviciului este numele fişierului descriptor .xml din subdirectorul services al directorului de resurse al aplicaţiei Web (WEBINF):

Client J#
package Tutorials.EjbStaff.NETClient; public class Client { /** @attribute System.STAThread() */ public static void main(String[] args) { EjbService.Exchange exchange = new EjbService.Exchange(); double rate = exchange.getRate("usa", "japan"); System.out.println("usa/japan exchange rate = " + rate); } }

7.2.5 Servicii Web virtuale Platforma Glue Professional permite publicarea unui descriptor WSDL pentru un serviciu Web virtual având la bază un set de interfeţe. Un serviciu virtual nu are ataşată o implementare statică în sensul consacrat; în schimb se oferă posibilitatea înregistrării unor clase care să trateze la momentul apelului mesajele SOAP destinate serviciului virtual. Această legare poate fi de nivel înalt sau de nivel scăzut. Legarea de nivel înalt utilizează clasa VirtualService, în timp ce legarea de nivel scăzut face apel la clasa VirtualSOAPHandler. Implementarea unui serviciu virtual High-Level se declară metodele interfeţei serviciu:
package tutorials.services.virtual; public interface IExchange { public double getRate(String country1, String country2); }

99

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

se oferă cel puţin o implementare pentru interfaţa serviciu. Arhitectura serviciilor virtuale High-Level are la bază mecanismul fabricii de obiecte. Spre deosebire de serviciile Web obişnuite care ataşează o singură implementare unei interfeţe publicate, serviciile virtuale permit ataşarea la momentul apelului a implementării adecvate contextului cererii:
package tutorials.services.virtual; public class Exchange implements IExchange { public double getRate(String country1, String country2) { return Math.random() * 100; } }

tratarea legării implementării concrete de interfaţa publicată nu mai are loc în descriptorul aplicaţiei sau în aplicaţia gazdă, ci într-o clasă specială care se foloseşte de mecanismul de Reflection pentru dispecerizarea apelurilor metodelor serviciului către obiectul ce-l deserveşte la momentul apelului:
package tutorials.services.virtual; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ExchangeHandler implements InvocationHandler { private IExchange exchange = new Exchange(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(exchange, args); } }

publicarea se poate face printr-un descriptor care precizează interfaţa şi handler-ul virtual sau printr-o aplicaţie consolă gazdă ce poate fi instalată să ruleze ca serviciu de platformă, în primul caz fiind nevoie de un server de aplicaţii gazdă, gen Glue sau un container pentru Glue (de exemplu Tomcat, JBoss, WebSphere, WebLogic etc.):
package tutorials.services.virtual; import electric.util.Context; import electric.registry.Registry; import electric.server.http.HTTP; import electric.service.virtual.VirtualService; public class ExchangePublish {

100

Reţele de calculatoare public static void main(String[] args) throws Exception

{

HTTP.startup("http://localhost:8004/glue"); ExchangeHandler handler = new ExchangeHandler(); VirtualService exchange = new VirtualService(IExchange.class, handler); Context context = new Context(); Registry.publish("exchange", exchange, context); } }

clientul apelează serviciul virtual similar apelării unuia obişnuit, prin legarea la URL-ul descriptorului WSDL şi conversia obiectului proxy obţinut la tipul interfeţei serviciului, prin care ulterior poate apela metodele acestuia, indiferent de clasa care le implementează pe server:
package tutorials.services.virtual; import electric.registry.Registry; public class ExchangeInvoke { public static void main(String[] args) throws Exception { String url = "http://localhost:8004/glue/exchange.wsdl"; IExchange exchange = (IExchange) Registry.bind(url, IExchange.class); double rate = exchange.getRate("usa", "japan"); System.out.println("usa/japan exchange rate = " + rate); } }

Implementarea unui serviciu virtual Low-Level un serviciu virtual de tip Low-Level implementează interfaţa electric.SOAP.ISOAPHandler pentru a răspunde apelurilor SOAP către metodele serviciului:
package tutorials.services.virtual; import java.rmi.RemoteException; import electric.xml.Element; import electric.xml.XPath; import electric.xml.io.encoded.EncodedWriter; import electric.SOAP.ISOAPHandler; import electric.SOAP.SOAPMessage;

101

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE import electric.util.Context; public class ExchangeSOAPHandler implements ISOAPHandler { static final XPath country1 = new XPath("getRate/[1]"); static final XPath country2 = new XPath("getRate/[2]"); public SOAPMessage handle(SOAPMessage request, Context context) throws RemoteException, SecurityException { String arg0 = request.getBody().getElement(country1).getString(); String arg1 = request.getBody().getElement(country2).getString(); SOAPMessage response = new SOAPMessage(); Element body = response.addBody(); Element result = body.addElement(); result.setNamespace("n", "http://tempuri.org/examples.publish.IExchange"); result.setName("n", "getRateResponse"); EncodedWriter writer = new EncodedWriter(result); writer.writeDouble("Result", Math.random() * 100); return response; } }

publicarea presupune înregistrarea interfeţei şi a handler-elor aferente, dintre care esenţial este cel care tratează mesajele SOAP şi prin intermediul căruia răspunde de fapt serviciul:
package tutorials.services.virtual; import electric.registry.Registry; import electric.server.http.HTTP; import electric.SOAP.virtual.VirtualSOAPHandler; public class ExchangeSOAPPublish { public static void main(String[] args) throws Exception { HTTP.startup("http://localhost:8004/glue"); ExchangeHandler invokeHandler = new ExchangeHandler(); ExchangeSOAPHandler SOAPHandler = new ExchangeSOAPHandler(); VirtualSOAPHandler exchange = new VirtualSOAPHandler(IExchange.class, invokeHandler, SOAPHandler); Registry.publish("exchange", exchange); } }

102

Reţele de calculatoare

apelarea unui serviciu virtual de tip Low-Level este similară apelării oricărui serviciu Web XML, clientul neştiind detaliile implementării serviciului. 7.2.6 Autentificarea şi autorizarea accesului Autentificarea presupune identificarea utilizatorului, adică verificarea identităţii utilizatorului. Pe platforma .NET avem trei categorii de autentificări, categorii dictate de cine anume implementează mecanismul de autentificare: IIS: Internet Information Server oferă următoare tipuri de autentificări: Anonymous Basic Authentification Digest Authentification Integrated Windows Authentification (NTLM sau Kerberos) ASP.NET: introduce două noi mecanisme de autentificare: Forms: dezvoltatorul creează o pagină prin care se cere utilizatorului să-şi introducă informaţiile de identificare. Pe baza unei proceduri de validare a datelor introduse se decide dacă este autentificat sau nu. Passport: autentificarea utilizatorului se face cu ajutorul unei terţe părţi; pentru detalii despre cum anume se poate implementa acest mecanism de autentificare vezi www.passport.com Antete SOAP personalizate: prin care dezvoltatorul îşi implementează propriul mecanism de autentificare. De exemplu, informaţiile despre utilizator să fie trimise sub formă de parametri la metoda serviciului web. Etapele autentificării de tip antete SOAP personalizate: crearea unui antet SOAP prin derivarea unei clase din SOAPHeader conţinând credenţiale criptate; crearea şi înregistrarea în web.config a unui modul HTTP care să implementeze metoda Init şi evenimentele Register ale interfeţei IHttpModule; tratarea evenimentului Custom Authentification în Global.asax verificându-se dacă informaţiile de autorizarea accesului nu există deja în colecţia Context.Cache. Dacă nu sunt stocate în cache-ul aplicaţiei informaţii despre rolul utilizatorului, atunci se construieşte un obiect de tip Credentials care se ataşează unui obiect de tipul Principal declarat ca utilizator curent al aplicaţiei prin încărcarea 103

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

obiectului Context.User. Verificarea contextului de rulare al aplicaţiei se face prin intermediul atributelor PrincipalPermission asociat metodelor expuse de serviciu Web. Autorizarea presupune acordarea drepturilor corespunzătoare rolului jucat de fiecare utilizator autentificat în sistem şi vizează mai multe niveluri de acces la resurse, şi anume: URL Authorization; File Authorization; Principal Permissions; .NET Roles. Platforma GLUE oferă suport pentru autentificarea pe client şi pe server, fiind compatibilă cu majoritatea platformelor care utilizează autentificarea de tip HTTP. În varianta Professional, GLUE include suport pentru integrarea cu standardul JAAS, care permite autentificarea bazată pe sistemul drepturilor de acces LDAP/NT. Noţiunile fundamentale pentru implementarea autentificării pe platfoma GLUE sunt: Principal, entitate asociată identităţii utilizatorului; Role, colecţie de drepturi de acces asociată unei identităţi a utilizatorilor autentificaţi; Permission, o acţiune care poate fi executată de un utilizator având un asociat un anumit rol; Realm, o colecţie de informaţii vizând identitatea utilizatorului, rolul asociat şi permisiunile aferente; Guard, o constrângere care utilizează o colecţie Realm pentru a verifica că un utilizator autentificat are dreptul să execute o anumită acţiune. Pentru impementarea autentificării şi autorizării accesului pe platforma GLUE se au în vedere următoarele etape: se editează fişierul WEB-INF/glue-config.xml în care se precizează tipul autentificării, în acest caz JAAS:
<realm> <constructor> o <class>electric.security.jaas.JAASRealm</class> o <args> <name>jaas</name> <config>security\jaas.config</config> o </args> </constructor> </realm> se editează fişierul WEB-INF/services/serviciu.xml în care se

specifică publicarea autentificării şi rolul aferent: 104

Reţele de calculatoare <publish>yes</publish> <role>denumire_rol</role> se editează fişierul WEB-INF/web.xml în care se precizează

metoda de autentificare:
<login-config> <realm-name>acl</realm-name> </login-config>

Pentru autentificarea apelului la un serviciu Web securizat se utilizează obiectul ProxyContext care va fi încărcat cu datele de autentificare ale utilizatorului declarat în fişierele de configurare, astfel:
ProxyContext context = new ProxyContext(); context.setAuthUser("denumire_rol"); context.setAuthPassword("parolă"); ISample sample = (ISample) Registry.bind(ur_wsdll, ISample.class, context);

7.3 Nivelul de prezentare 7.3.1 Construirea unei imagini într-o pagină ASP.NET Pentru exemplificare vom considera o pagină ASP.NET care afişează ca rezultat o imagine extrasă dintr-o bază de date şi primită de la un serviciu Web sub forma unui vector de octeţi. Pagină ASP.NET cu Code Behind
<%@ Page language="c#" Codebehind="RoomImage.aspx.cs" AutoEventWireup="false" Inherits="Tutorials.AspNet.RoomImage" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <html> <head> <title>RoomImage</title> <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body MS_POSITIONING="GridLayout"> <form id="ImageForm" method="post" runat="server"> </form> </body> </html>

105

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

o pagină Web extinde clasa System.Web.UI.Page; are acces la interfaţa server-ului Web prin obiecte de forma Request, Response, Session, Context etc; punctul de intrare în program este handler-ului evenimentului Load al paginii, în acest caz funcţia Page_Load; Clasa paginii
using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.IO; namespace Tutorials.AspNet { public class RoomImage : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { if(this.Request["RoomId"]!=null) { this.Response.ContentType = "image/jpg"; Administrator.AdministratorService service = new Administrator.AdministratorService(); byte[] image = service.GetRoomImageData(int.Parse(this.Request["RoomId"])); if(image == null) { FileStream fileStream = new FileStream(this.Server.MapPath("tmp/admin_no_image.jpg"), FileMode.Open); image = new byte[new FileInfo(this.Server.MapPath("tmp/admin_no_image.jpg")).Length ]; fileStream.Read(image, 0, image.Length); fileStream.Close(); }

106

Reţele de calculatoare

this.Response.OutputStream.Write(image, 0, image.Length); } } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { InitializeComponent(); base.OnInit(e); } private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } }

7.3.2 Apelarea unei componente dintr-un servlet Tehnologia Servlet a fost gândită să suplinească deficienţele arhitectuiri CGI legate de gestiunea proceselor şi firelor de execuţie, precum şi de securitate, având următoarele caracteristici funcţionale: pune la dispoziţia programatorului obiecte pentru accesarea interfeţei server-ului Web cum ar fi HttpServletRequest, HttpServletResponse etc., organizate în pachetele javax.servlet şi javax.servlet.http; răspunsul generat la ieşire devine sursa paginii HTML, astfel încât un servlet nu separă procesările şi conţinutul rezultat de formatarea acestuia; binarele unui servlet trebuie publicate în subdirectorul WEBINF/classes al unui context Web; pentru a putea fi accesat, servletului i se asociază un URL prin intermediul fişierului de configurare web.xml sau cu ajutorul meta-tag-ului comentariu @web.servlet-mapping, dacă se utilizează un mediu de construire a arhivei .war cum ar fi Ant sau XDoclet. Servlet care accesează o componentă EJB
package tutorial.web; import java.io.IOException; import java.io.PrintWriter;

107

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE import javax.naming.Context; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import tutorial.interfaces.Fibo; import tutorial.interfaces.FiboHome; /** * @web.servlet name="Compute" display-name="Computation Servlet" * description="Servlet that compute Fibonacci suite" * * @web.servlet-mapping url-pattern="/Compute" * * @web.ejb-ref name="ejb/Fibo" type="Session" * home="tutorial.interfaces.FiboHome" * remote="tutorial.interfaces.Fibo" description="Reference to the * Fibo EJB" * * @jboss.ejb-ref-jndi ref-name="ejb/Fibo" jndiname="ejb/Fibo" */ public class ComputeServlet extends HttpServlet { private FiboHome home; public ComputeServlet() { super(); } public void init(ServletConfig config) throws ServletException { try { Context context = new InitialContext(); Object ref = context.lookup("java:/comp/env/ejb/Fibo"); home = (FiboHome) PortableRemoteObject.narrow(ref, FiboHome.class); } catch (Exception e) { throw new ServletException("Lookup of java:/comp/env/ failed"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

108

Reţele de calculatoare response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><head><title>"); out.println("Fibonaci Computation"); out.println("</title></head>"); out.println("<body>"); out.println("<h1>"); out.println("Fibonaci Computation"); out.println("</h1>"); try { Fibo bean = home.create(); int limit = 0; String value = request.getParameter("limit"); if (value != null) { try { limit = Integer.parseInt(value); } catch (Exception e) { } } double[] result = bean.compute(limit); bean.remove(); out.println("<p>"); out.print("The "); out.print(limit); out.print(" first Fibonacci numbers "); for (int i = 0; i < result.length; i++) { out.println("<br>"); out.println(i); out.println(" : "); out.println(result[i]); } out.println("</p>"); } catch(Exception e) { out.println(e.getMessage()); e.printStackTrace(out); } finally { out.println("</body></html>"); out.close(); } } }

109

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

7.3.3 Definirea unui Custom Tag în JSP Tehnologia JSP a fost dezvoltată din Servlet cu scopul separării prelucrărilor şi conţinutului de formatarea rezultatelor, având următoarele caracteristici: permite intercalarea de cod procesat pe server cu formatări HTML; la momentul primei cereri o pagină JSP este translatată într-un servlet de către serverul de aplicaţii, care este apoi compilat în cod de octeţi şi interpretat; pentru orice altă cerere se compară data salvării paginii JSP cu data fişierului binar generat, verificându-se astfel dacă este necesară translatarea şi recompilarea paginii; Principiul separării procesărilor de formatarea rezultatelor este cel mai bine exemplificat în standarduol JSP 2.0 de tehnologia Custom Tags. Pentru implementarea unui Custom Tag este necesară scrierea următoarelor componente: o clasă tag handler: reprezintă o clasă Java care precizează modul în care tag-ul produce rezultat HTML; extinde clasa TagSupport sau BodyTagSupport şi implementează interfaţa Tag din pachetul javax.servlet.jsp.tagext, fiind publicată în contextul aplicaţiei împreună cu celelalte clase şi componente Bean ale acesteia; un fişier descriptor al bibliotecii de tag-uri: descrie în format XML numele, atributele şi handler-ele tag-urilor, fiind publicat împreună cu paginile JSP sau pe o anumită adresă URL dacă aparţine altui context decât cel al aplicaţiei Web curente; fişierele JSP: importă biblioteca de tag-uri prin intermediul fişierului descriptor, asociindu-i un prefix de tag pentru a putea utiliza tag-uri ale acesteia în codul JSP. Implementarea handler-ului tag-ului necesită: extinderea clasei TagSupport din pachetul javax.servlet.jsp.tagext; rescrierea metodei doStartTag; se obţine o referinţă la obiectul JspWriter al fluxului de procesare a ieşirii paginii, prin care se generează conţinutul JSP; metoda întoarce constanta SKIP_BODY în cazul unui tag simplu, fără imbricări de tip corp de tag;

110

Reţele de calculatoare

codul este translatat în servlet la momentul primei cereri a paginii JSP, generând apoi răspuns HTML prin execuţie pentru fiecare cerere în parte. Custom Tag fără imbricare
package tutorials.customtags; import java.io.IOException; import java.util.Random; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; public class SimpleRandomTag extends TagSupport { protected int length; public int doStartTag() { try { JspWriter out = this.pageContext.getOut(); out.print(new Random().nextInt(this.length)); } catch(IOException exception) { System.out.println(exception.toString()); } return SKIP_BODY; } }

Se scrie apoi descriptorul XML al bibliotecii de tag-uri custom, atfel: după antetul documentului XML cu DOCTYPE, tag-ul rădăcină este taglib; fiecare tag este definit de elementul tag precizând numele tag-ului şi handler-ul care-l tratează; nodul name precizează numele tag-ului curent; nodul tagclass indică numele clasei handler calificat cu pachetul acesteia; nodul info conţine o scurtă descriere a tag-ului curent. Descriptor pentru biblioteca de tag-uri custom
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tag> <name>simpleRandom</name>

111

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE <tagclass>tutorials.customtags.SimpleRandomTag</tagclass> <info>Outputs a random integer.</info> </tag> </taglib>

Utilizarea unui tag dintr-o bibliotecă într-o pagină JSP presupune: se importă biblioteca de tag-uri precizând locaţia acesteia relativă la contextul aplicaţiei sau absolută:
<%@ taglib uri="customjsp-taglib.tld" prefix="customjsp" %>

se defineşte un prefix asociat bibliotecii importate
<prefix:tagName />

se apelează tag-uri din bibliotecă prefixate corespunzător importului
<customjsp:simpleRandom />

Pagină JSP care utilizează un Custom Tag
<%@page contentType="text/html" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%@ taglib uri="/WEB-INF/jsp/CustomTags.tld" prefix="mytags" %> <html> <head> <title>JSP Page</title> </head> <body bgcolor="#FFFFFF"> <mytags:simpleRandom/> </body> </html>

Acest mecanism poate fi extins sub forma unui custom tag cu atribute şi conţinut: se declară în handler-ul tag-ului proprietăţi pentru fiecare atribut al său; setarea unui atribut în cadrul tag-ului echivalează cu apelarea metodei setter a obiectului handler; se declară atributul în descriptorul tag-ului 112

Reţele de calculatoare

Custom Tag care extinde un tag simplu prin adăugarea unui atribut
package tutorials.customtags; public class RandomTag extends SimpleRandomTag { public void setLength(int length) { this.length = length; } }

Descriptor pentru un Custom Tag cu atribute
<tag> <name>random</name> <tagclass>tutorials.customtags.RandomTag</tagclass> <attribute> <name>length</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute>

</tag>

7.4 Interoperabilitatea platformelor .NET şi J2EE Pe piaţa platformelor software pentru aplicaţii distribuite de întreprindere există în prezent două mari clase consacrate: .NET şi J2EE. Deşi din raţiuni de compatibilitate şi integrare am fi tentaţi să optăm pentru o soluţie omogenă când se pune problema implementării unui sistem de întreprindere, totuşi teoria avantajului comparativ evidenţiază necesitatea cooperării celor mai bune tehnologii pentru fiecare nivel în parte. Interoperabilitatea celor două platforme este necesară din următoarele considerente practice: eterogenitatea platformelor hardware şi software existente în mediul de întreprindere; controlul total este ineficient; specificul aplicaţiei trebuie avut în vedere la alegerea unei platforme; ca rezultat, majoritatea companiilor combină tehnologiile; la baza oricărui demers de combinare a platformelor software stă satisfacerea nevoilor clienţilor într-o măsură cât mai mare.

113

Implementarea aplicaţiilor distribuite pe platformele .NET şi J2EE

Potrivit percepţiei comune o aplicaţie eterogenă care se bazează pe cele două platforme ar trebui să folosească tehnologii .NET pe partea de client şi tehnologii J2EE pe partea de server, deoarece: soluţia .NET este mai bună pe partea de client, având drept atuuri: interfaţa client adaptată şi optimizată pentru platforma Windows, folosită de majoritatea utilizatorilor finali ai produselor informatice de întreprindere; oferă suport extins pentru dispozitive mobile şi protocoale dedicate gen WAP; se integrează cu suita de aplicaţii Office. pe de altă parte, soluţia J2EE este potrivită pentru nivelurile logicii aplicaţiei şi de acces la date, deoarece: oferă o performanţă ridicată, având un grad înalt de scalabilitate; este mai mentenabilă decât .NET; are un raport calitate / preţ superior, oferind soluţii fiabile. Această abordare nu este întotdeauna cea optimă. Se pot imagina trei scenarii de interoperabilitate plauzibile: punte RMI – .NET Remoting: are drept principal avantaj performanţa ridicată a comunicaţiei, putând utiliza o gamă foarte largă de protocoale peste TCP, unele chiar împachetate binar şi arhivate; ca dezavantaje se remarcă complexitatea ridicată, necesitând convertoare de protocol, proprietatea obiectelor COM+ pe platforma .NET precum şi dependenţa de versiunea obiectelor. apelul prin cozi de mesaje: prezintă avantajul cuplării slabe, permiţând comunicarea intra şi inter-niveluri, în condiţiile existenţei unui suport extins pentru tranzacţii şi securitate; ca principal dezavantaj se înscrie absenţa operaţiilor sincrone, introducându-se penalizări temporare semnificative pentru sincronizare, alături de posibile neajunsuri de acces pe porturi prin Firewall.

114

Cuprins
4 5 6 8 9 10 10 10 11 12 18 19 19 19 21 22 26 27 30 30 33 34 35 35 39 43 43 44 48 52 53 65

1. Introducere .....................................................................................................

1.1. Modelul client - server .........................................................................................................

1.2. URL. Scheme URL .................................................................................................................

1.3. Hipertext, hiperlegătură, hipermedia .............................................................................

1.4. Protocolul HTTP (Hypertext Transfer Protocol) ..........................................................

2. FTP şi poşta electronică ...............................................................................
2.1.1. Server FTP ................................................................................................................ 2.1.2. Client FTP .................................................................................................................

2.1. Serviciul FTP – transfer de fişiere ..................................................................................

2.2. Serviciul de poştă electronică – e-mail ...........................................................................

2.3. Exerciţii ..................................................................................................................................

3. Servere WEB ..................................................................................................

3.1. Introducere ............................................................................................................................

3.2. IIS ...........................................................................................................................................

3.3. Exerciţii IIS .........................................................................................................................

3.4. NCSA .......................................................................................................................................

3.5. Apache ....................................................................................................................................

3.6. Exerciţii NCSA, Apache .....................................................................................................

4. Utilitare TCP - IP ..........................................................................................

4.1. Utilitare TCP - IP ..................................................................................................................

4.2. Testarea unei configuraţii TCP - IP .................................................................................

4.3. Exemple de folosire a unor utilitare TCP - IP ...............................................................

5. Adresare IP ....................................................................................................

5.1. Clase de adrese .....................................................................................................................

5.2. Exerciţii rezolvate ...............................................................................................................

6. Comunicare client – server la nivel de socket .........................................

6.1. Introducere ............................................................................................................................ 6.2.1. Comunicaţie client – server TCP - IP ................................................................. 6.2.2. Comunicaţie client – server UDP - IP ................................................................

6.2. Interfaţa socket ..................................................................................................................

6.3. Exemplificări .........................................................................................................................

7. Implementarea aplicaţiilor distribuite pe platformele .NET şi

7.2.2. Serializarea tipurilor de date complexe .......................................................... 7.2.3. Apelarea serviciilor WEB în mod asincron ....................................................... 7.2.4. Publicarea unei componente ca serviciu WEB ................................................. 7.2.5. Servicii WEB virtuale ............................................................................................ 7.2.6. Autentificarea şi autorizarea accesului ........................................................... 7.3.1. Construirea unei imagini într-o pagină ASP.NET ............................................. 7.3.2. Apelarea unei componente dintr-un servlet .................................................... 7.3.3. Definirea unui Custom Tag în JSP .....................................................................

7.3. Nivelul de prezentare ..........................................................................................................

7.4. Interoperabilitatea platformelor .NET şi J2EE ..........................................................

Bibliografie ..........................................................................................................

86 90 94 99 103 105 105 107 110 113 116

Reţele de calculatoare

servicii Web: se remarcă drept varianta optimă de interoperabilitate pentru cele mai multe situaţii datorită cuplării slabe, în condiţiile executării de operaţii sincrone, cât şi asincrone, fără restricţii de tip Firewall sau conversii de protocoale de comunicaţie; până în prezent are totuşi dezavantajul implementării parţiale a standardelor pentru securitate, dar mai ales pentru tranzacţii. Dezvoltarea modelului GXA (Global XML Web Services Architecture) intenţionează să înlăture aceste neajunsuri prin protocoale de tipul WS-Security, WS-Attachement sau WS-Routing.

115

Bibliografie
1. 2. 3. 4. 5. BURAGA, S. CIOBANU, G. CRAWFORD W., KAPLAN, J. GULZAR, N., GANESHAN, K. JURCA, I. MCLEAN, S., NAFTEL, J., WILLIAMS, K. MONSON-HAEFEL, R. NĂSTASE, F., NĂSTASE, P. NĂSTASE, F. PELTZER, D. Atelier de programare în reţelele de calculatoare, Iaşi, Editura Polirom, 2001; J2EE Design Patterns, O’Reilly, 003; Practical J2EE Application Architecture, McGraw-Hill, 2003; Programarea reţelelor de calculatoare, Timişoara, Editura de Vest, 2001; .NET Remoting, MS Press, 2003;

6. 7. 8. 9.

J2EE Web Services, Addison-Wesley, 2003; Tehnologia aplicaţiilor WEB, Bucureşti, Editura Economică, 2002; Arhitectura reţelelor de calculatoare, Bucureşti, Editura Econmică, 1998 .NET & J2EE Interoperability, McGraw-Hill, 2004; .NET for Java Developers: Migrating to C#, Addison Wesley, 2003; Advanced .NET Remoting, APress, 2002;

10. PUVVALA, J., POTA, A. 11. RAMMER, I.

116

Bibliografie

12. ROŞCA, I., ŢĂPUŞ, N., CRISTEA, V., ATANASIU, I., NĂSTASE, Fl., PAIU, O., STANCIU, C., COSTINESCU, B., GODZA, G., 13. STANCIU-TIMOFTE, C.

INTERNET & INTRANET - Concepte şi aplicaţii, Bucureşti, Editura Economică, 2000;

Baze de date pentru comerţ electronic pe suport Internet, Bucureşti, Editura Oscar Print, 2002; J2EE 1.4 Tutorial, Sun Microsystems, 2003.

14. * Sun

Resurse Apache: Tomcat, Struts – http://www.apache.org Eclipse: Eclipse SDK – http://www.eclipse.org IBM: WSDK – http://www.ibm.com JBoss: JBoss Server, JBoss IDE for Eclipse – http://www.jboss.org Microsoft: .NET SDK, UDDI SDK, MSDE –
http://www.microsoft.com

Mono: .NET Framework for Linux – http://www.go-mono.com MySQL: MySQL Server, ADO.NET Providers, JDBC Drivers –
http://www.mysql.com

Sun: J2SDK, J2EE, JWSDP – http://java.sun.com WebMethods: Glue – http://www.webmethods.com

117