Sunteți pe pagina 1din 12

Sisteme distribuite.

Socket-uri
O reea este format dintr-o mulime de calculatoare i periferice (imprimante, plotere, scannere, modemuri etc.) conectate ntre ele. Un sistem distribuit este o colecie de calculatoare i/sau procesoare autonome (avnd o unitate de comand proprie), interconectate (capabile de a schimba informaii ntre ele). Elementele coleciei poart numele de noduri. Un astfel de sistem poate fi programat pentru a rezolva probleme de concuren i de paralelism. Sistemele distribuite au aprut ca o necesitate pentru: - schimbul de informaii ntre noduri; - partajarea unor resurse (printere, memorie backup, uniti de disc etc.); - sigurana n funcionare: dac un nod "cade", ntregul sistem trebuie (dac este posibil) s fie capabil s asigure n continuare funcionarea, prin redirijarea (rutarea) mesajelor prin nodurile funcionale. Tipuri de reele O prim clasificare a reelelor este constituit de mprirea lor n reele LAN (Local Area Network) i reele WAN (Wide Area Network). Reelele LAN sunt folosite de obicei pentru a partaja resurse (fiiere i periferice) i de a facilita schimbul de informaii ntre nodurile componente. Conectarea tipic este realizat prin cablu, cu o limit dat pentru un drum ntre dou noduri (de exemplu 10 km). La fiecare moment de timp, ntr-o astfel de reea este transmis un singur mesaj. Numele reelei desemneaz produsul i nu reeaua (aa cum se ntmpl la reelele WAN). De exemplu Ethernet este un produs al companiei XEROX. Probleme algoritmice pentru astfel de reele: 1) sincronizarea: ateptarea ndeplinirii unei condiii; 2) difuzarea total (broadcasting) : transmiterea unui mesaj ctre toate celelalte noduri; 3) selectarea unui proces pentru ndeplinirea anumitor aciuni; 4) detectarea terminrii: un nod ce ntreprinde o aciune, n care antreneaz i alte noduri, trebuie s fie capabil s detecteze momentul ncheierii aciunii; 5) excluderea reciproc: utilizarea unor resurse sub excludere reciproc (de exemplu modificarea unui fiier sau scrierea la imprimant); 6) detectarea i prevenirea blocrii totale (deadlock); 7) gestionarea distribuit a fiierelor. Reelele WAN permit comunicarea pe distane mai mari, prin legturi directe ntre noduri, realizate prin linie telefonic, fibr optic, legtur via satelit etc. Ele sunt grafuri orientate. Probleme algoritmice pentru astfel de reele: 1) sigurana schimbului de informaii pe fiecare arc al grafului. Informaia eronat trebuie recunoscut ca atare i corectat. Menionm c este posibil ca

mesajele s soseasc ntr-un nod n alt ordine dect cea n care au fost transmise, pot fi duplicate etc.; 2) selectarea de ci de comunicare (rutare) ntre nodurile care schimb informaii, deoarece un graf complet este prea costisitor i n general nici nu este realizabil. Modul de rutare trebuie actualizat n cazul n care un nod al reelei cade (devine nefuncional); 3) evitarea congestionrii unor ci de comunicaie, realizat tot prin (re)rutare; 4) evitarea blocrii totale; 5) securizarea datelor i a transmisiilor. Deosebirile eseniale ntre cele dou tipuri de reele se refer la: 1) securizare: n reele LAN se presupune c transmiterea este corect, pe cnd n reelele WAN trebuie presupus c n timpul transmiterii mesajelor se poate ntmpla "ceva ru"; 2) timpul de comunicare: n reelele WAN timpul de comunicare este mult mai mare (de 10k ori mai mare, k 1) dect n reelele LAN; aceast timp este la rndul su mult mai mare dect cel cerut de prelucrrile locale; 3) omogeneitatea: n reelele WAN trebuie presupus c sunt utilizate simultan mai multe protocoale (vezi paragraful urmtor), ceea ce pune problema recunoaterii i conversiei ntre ele; 4) ncrederea reciproc: nu este presupus n reelele WAN i drept urmare trebuie luate msuri de securitate adecvate. Protocoale Comunicarea ntre componentele unei reele (respectiv unui sistem distribuit) se face prin mulimi de reguli, numite generic protocoale. Un protocol cuprinde att formatul mesajului ce este efectiv transmis, ct i modul n care trebuie rspuns la mesajul respectiv. Protocolul folosit pe Internet este IP (Internet Protocol). Mesajele circul n pachete, ce pot fi: - pachete Internet, pentru care protocolul este TCP (Transmission Control Protocol); - datagrame, pentru care protocolul este UDP (User Datagram Protocol); nu vom vorbi despre ele. Internetul folosete nume (adrese) simbolice pentru reele i pentru mainile gazd; ele se mai numesc nume de domeniu. Lor li se asociaz n mod biunivoc adrese (numerice) IP, folosite efectiv la comunicarea ntre nodurile reelei. Asocierea cade n sarcina unui sistem de nume de domeniu (DNS = Domain Name System). O adres numeric IP are foma:
a.b.c.d unde a, b, c, d sunt numere naturale din mulimea {0, 1, ..., 255}.

Modelul Client/Server Dup cum tim, comunicarea ntre nodurile unei reele const n transmiterea (recepionarea) de pachete ctre (de la) gazde ale aceleai reele sau ale unei alte reele. Modelul utilizat pe scar larg n sistemele distribuite (i care va fi cel folosit n continuare) este sistemul Client/Server. n acest model exist: - o mulime de procese Server, fiecare jucnd rolul de gestionar de resurse pentru o colecie de resurse de un anumit tip; - o mulime de procese Client; fiecare execut activiti care necesit acces la resurse hard/soft disponibile (partajate) de servere. Un gestionar de resurse poate avea i el nevoie de resurse gestionate de un alt proces Server. Drept urmare, unele procese pot fi att de tip Client, ct i de tip Server. Dar doar serverele gestioneaz resurse. Serverele sunt cele care i ncep primele activitatea. n mod tipic, un server ofer succesiv clienilor posibilitatea de a se conecta la el (spunem c accept conexiuni de la clieni). La nceput clientul i manifest dorina de a se conecta i, dac serverul este gata s accepte conexiunea, aceasta se realizeaz efectiv; este vorba deci de o aciune de la client ctre server. Apoi transmisia informaiilor devine bidirecional, fluxul de informaii putnd circula acum n ambele sensuri. Teoretic, activitatea unui server se desfoar la infinit. Pentru conectare la server, clientul trebuie s cunoasc adresa serverului (fie cea numeric, fie cea simbolic), precum i numele portului pus la dispoziie de server. Portul nu este o locaie fizic, ci o extensie software corespunztoare unui serviciu. Serverul poate oferi mai multe servicii, pentru fiecare existnd un numr de port. Cel standard sunt: 7 : ping (ecou) 21 : ftp (transfer de fiiere) 23 : telnet 25 : email 79 : finger 80 : Web 110 : POP3 (Post Office Protocol) Porturile din intervalul 0..1023 sunt n general rezervate pentru servicii speciale (de genul celor de mai sus) i pentru clieni privilegiai. Clientul iniiaz conexiunea prin reea, specificnd adresa serverului i portul prin care dorete s comunice. Serverul trebuie s precizeze numai portul; apoi el trebuie s execute o comand prin care s anune c este gata s accepte conexiuni pe portul respectiv; drept urmare el rmne n ateptare pn cnd un client dorete s se conecteze i conexiunea este stabilit cu succes. Un server poate accepta conexiuni de la mai muli clieni: pentru fiecare creaz un fir de executare.

Clasa InetAddress

Aceast clas, aflat n pachetul java.net, furnizeaz informaii asupra adreselor (simbolic i numeric) unui calculator gazd. Clasa nu are constructori publici. Principalele metode sunt:
public static InetAddress getLocalHost()

returneaz numele calculatorului gazd (pe care se afl n curs de executare aplicaia). Acest nume, convertit la String, are forma: adres_simbolic/adres_IP;
public static InetAddress getByName(String s)

public String getHostName() public byte[] getAddress()

dndu-se ca argument adresa simbolic sau numeric a calculatorului gazd, metoda ntoarce un obiect de tipul InetAddress; metoda poate lansa excepia UnknownHostException; ntoarce adresa simbolic a calculatorului gazd; ntoarce un tablou de 4 octei, ce compun adresa numeric.

Exemplul 1. Determinarea adreselor unui calculator i obinerea uneia dintre aceste adrese cunoscnd-o pe cealalt:
import java.net.*; class Adrese { public static void main(String[] sss) throws Exception { InetAddress gazda = null; gazda = InetAddress.getLocalHost(); System.out.println(gazda.toString()); } }

ntrebare. "Are sens s studiem facilitile oferite de Java pentru lucru n reea dac avem la dispoziie un singur calculator?". DA! Putem de exemplu deschide mai multe ferestre de comand. Adresa IP: numele calculatorului, numele standard "localhost" sau "127.0.0.1".

Comunicare prin socket-uri


Socket-urile sunt folosite pentru transmiterea de date folosind protocolul TCP/IP. Ele sunt obiecte ce trebuie create la ambele capete ale conexiunii. Socketurile client sunt obiecte de tipul clasei Socket, iar socket-urile server sunt obiecte de tipul clasei ServerSocket; ambele clase fac parte din pachetul java.net. Socketurilor li se pot ataa un flux de intrare i unul de ieire, prin care pot recepiona/ transmite, date. Prezentm n continuare schema general a lucrului cu socket-uri, apelnd la facilitile de intrare/ieire la nivel de octet. Un mod tipic de creare a unui socket client este urmtorul:
try { Socket cs = null; cs = new Socket("adresa",nrport); InputStream is = cs.getInputStream(); OutputStream os = cs.getOutputStream(); } catch(UnknownHostException e) { ... } catch(IOException e) { ... }

unde adresa este adresa IP a serverului, iar nrport este numrul portului ales pentru comunicare. Socket-ului i sunt ataate fluxul os ce va fi folosit pentru a transmite date serverului, precum i fluxul is ce va fi folosit pentru recepionarea datelor transmise de server. Dup caz, fluxurile vor fi nzestrate cu facilitile de transmitere a datelor primitive, a obiectelor etc., folosind tehnica suprapunerii fluxurilor. Un mod tipic de creare a unui socket server este urmtorul:
ServerSocket ss = null; Socket cs = null; try { ss = new ServerSocket(nrport); // System.out.println("Serverul a pornit"); } catch(IOException e) { ... } try { cs = ss.accept(); InputStream is = cs.getInputStream(); OutputStream os = cs.getOutputStream(); } catch(UnknownHostException e) { ... } catch IOException e) { ... }

Observm c pentru server nu este necesar precizarea unei adrese IP, ci numai a unui port, care trebuie s coincid cu cel folosit de client. Metoda accept lucreaz astfel: se atept ca un client s ncerce s se lege la server pe portul precizat; n momentul n care acest lucru se ntmpl i legtura s-a stabilit, metoda creeaz i ntoarce un socket cs de tip client. Acestuia i atam un flux de intrare i unul de ieire. Ca i pentru client, fluxurile pot fi nzestrate cu facilitile de transmitere a datelor primitive, a obiectelor etc.
Client
os cs is is os cs ss

Server

n final toate socket-urile i fluxurile trebuie nchise explicit prin invocarea metodei close.

Clasa URL

Clasa URL este declarat n pachetul java.net prin: public final class URL extends Object implements Serializable Un obiect de tip URL, numit i locaie URL, este o referin la o resurs Web. Resursa poate fi un fiier, un director, dar i un obiect mai complex ca de exemplu o cerere ctre o baz de date sau un motor de cutare. Ca sintax, o astfel de adres cuprinde 4 pri:
protocol:// adresa :port /cale

unde protocol desemneaz serviciul exportat de server sau cutat de client (de exemplu http sau ftp), adresa este adresa simbolic sau numeric a mainii gazd referite, port portul folosit pentru comunicare, iar cale identific resursa. Un exemplu este urmtorul:
http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html

Sunt folosite i locaii URL pariale, ce specific doar unele pri din forma complet a locaiei; acest lucru este posibil n situaiile n care celelalte pri sunt implicite sau se deduc din context. De exemplu poate lipsi numele mainii gazd (dac facem referire la maina local) sau portul (dac este folosit un port implicit).
public URL(String protocol, String gazda, int port, String fisier) Metode (publice), ale clasei URL : String getPath()

Constructorul "complet" are forma:

ntoarce calea din locaia URL;


int getPort() String getProtocol() String getHost() String getFile()

ntoarce numrul portului din locaia URL; ntoarce protocolul din locaia URL; ntoarce adresa mainii gazd din locaia URL; ntoarce numele fiierului din locaia URL;

String toString()

ntoarce reprezentarea sub form de ir de caractere a locaiei URL. Exemplul 2. Dorim s aflm dac un server avnd o adres dat ofer sau nu servicii Web. Va fi creat un socket de tip client. Adresa este furnizat n comanda java.
// Executarea se face prin: java WebCheck adresa import java.io.*; import java.net.*; public class WebCheck { public static void main(String[] adresa) { Socket web = null; System.out.print("Serverul " + adresa[0]); try { web = new Socket(adresa[0],80); System.out.println(" ofera servicii Web"); web.close(); } catch(IOException e) { System.out.println(" nu ofera servicii Web"); } } }

Exemplul 3. Chat (o conversaie) ntre dou calculatoare. Pentru simplificare, considerm c fiecare mesaj trimis de la un calculator la cellalt se reduce la o linie de text. Serverul este primul care trebuie pornit. Apoi clientul este cel care ncepe discuia, transmind un mesaj i ateptnd s primeasc mesajul de rspuns, activiti care se repet pn cnd clientul transmite mesajul "STOP". Serverul repet i el succesiunea de activiti recepie + transmisie pn cnd primete mesajul "STOP". Clientul va folosi unitatea de compilare Client.java, iar serverul va folosi unitatea de compilare Server.java.
// Unitatea de compilare Client.java import java.net.*; import java.io.*; class Client { public static void main (String[] sir) throws IOException { Socket cs = null; DataInputStream is=null; DataOutputStream os=null; try { cs = new Socket("localhost",5678); is = new DataInputStream(cs.getInputStream()); os = new DataOutputStream(cs.getOutputStream()); } catch(UnknownHostException e) { System.out.println("Host inexistent"); } DataInputStream stdin = new DataInputStream(System.in); String linie; for( ; ; ) { linie = stdin.readLine()+"\n"; os.writeBytes(linie); System.out.println("Transmisie :\t" + linie); if (linie.equals("STOP\n")) break; linie = is.readLine(); System.out.println("Receptie :\t" + linie); } System.out.println("GATA"); cs.close(); is.close(); os.close(); } } // Unitatea de compilare Server.java import java.net.*; import java.io.*; class Server { public static void main (String[] sir) throws IOException { ServerSocket ss = null; Socket cs = null; DataInputStream is=null; DataOutputStream os=null; ss = new ServerSocket(5678); System.out.println("Serverul a pornit !"); cs = ss.accept(); is = new DataInputStream(cs.getInputStream()); os = new DataOutputStream(cs.getOutputStream()); DataInputStream stdin = new DataInputStream(System.in);

} }

String linie; for( ; ; ) { linie = is.readLine(); System.out.println("Receptie :\t" + linie); if (linie.equals("STOP")) break; linie = stdin.readLine()+"\n"; os.writeBytes(linie); } cs.close(); is.close(); os.close();

Observaie. Metoda readLine este considerat "depreciat" (deprecated). Exemplul 4. Dorim s descrcm un fiier aflat pe o pagin Web. Adresa serverului, portul (80 pentru servicii Web) i numele fiierului cutat vor fi specificate n aceast ordine n comanda java. Un exemplu este urmtorul:
java HTTPClient localhost 12345 1.doc GET nume_fiier

Practic, vom transmite serverului, sub forma unui ir de caractere, mesajul: ce reprezint o comand din limbajul HTTP (HyperText Transmission Protocol) i pe care un server de Web tie s o interpreteze corespunztor. Comanda GET trebuie urmat de o linie vid. Fiierul recepionat va fi inclus sub acelai nume n directorul curent.
// Unitatea de compilare HTTPClient.java import java.io.*; import java.net.*; class HTTPClient { public static void main(String[] sir) throws IOException { int port = Integer.parseInt(sir[1]); Socket cs = null; InputStream is = null; DataOutputStream dos = null; try { cs = new Socket(sir[0],port); is = cs.getInputStream(); dos = new DataOutputStream(cs.getOutputStream()); } catch(UnknownHostException e) { System.out.println("Host inexistent"); } String mesaj = "GET " + sir[2] + "\n\n"; dos.writeBytes(mesaj); OutputStream fis = new FileOutputStream(sir[2]); int c; while( (c=is.read()) != -1) { System.out.print("" + (char) c); fis.write(c); } fis.close(); is.close(); dos.close(); cs.close(); System.out.println("\nGata!");

} }

Exemplul 5. Crearea propriului server de Web. Dorim s crem propriul nostru server Web, capabil doar s rspund cererilor de descrcare a unui fiier efectuate prin comanda GET. Vom proceda astfel: citim prima linie din mesaj i, folosind StringTokenizer, extragem cele dou iruri de caractere. Dac primul dintre ele este GET, trecem la descrcarea fiierului al crui nume este al doilea ir de caractere i apoi mai citim o linie.
import java.io.*; import java.net.*; import java.util.*; // pentru StringTokenizer class HTTPServer { public static void main(String[] s) throws IOException { ServerSocket ss = new ServerSocket(12345); System.out.println("Serverul a pornit"); Socket cs = ss.accept(); System.out.print("Un client s-a conectat. Comanda: "); DataInputStream dis = new DataInputStream(cs.getInputStream()); OutputStream os = cs.getOutputStream(); String fisier = null, mesaj = dis.readLine(); System.out.println(mesaj); StringTokenizer st = new StringTokenizer(mesaj); String token = st.nextToken(); if (token.equals("GET")) fisier = st.nextToken(); dis.readLine(); int c; try { FileInputStream f = new FileInputStream(fisier); while( (c=f.read()) != -1) os.write(c); f.close(); cs.close(); dis.close(); os.close(); } catch(IOException e) { System.out.println("Eroare fisier cerut"); }

} }

Utilizarea firelor de executare la lucrul n reea


Revenim la serverul nostru de Web, capabil numai s trimit unui client unui fiier cerut prin comanda GET. Dezavantajul su este constituit n principal de faptul c serverul este capabil s serveasc un singur client. n programul urmtor, serverul va lansa cte un fir de executare pentru fiecare client ce se conecteaz la el. Va fi folosit portul 12345 pentru toi clienii.
import java.io.*; import java.net.*; import java.util.*; // pentru StringTokenizer class HTTPServer_n { public static void main(String[] arg) throws IOException { ServerSocket ss = null; Socket cs = null;

} }

ss = new ServerSocket(12345); System.out.println("Serverul a pornit"); while (true) { cs = ss.accept(); System.out.print("Client nou. Comanda: "); new Conexiune(cs); }

class Conexiune extends Thread { Socket cs = null; String linie; OutputStream os = null; DataInputStream dis = null; public Conexiune(Socket client) throws IOException { cs = client; dis = new DataInputStream(cs.getInputStream()); os = cs.getOutputStream(); start(); } public void run() { String mesaj = null, fisier = null; try { mesaj = dis.readLine(); System.out.println(mesaj); StringTokenizer st = new StringTokenizer(mesaj); String token = st.nextToken(); if (token.equals("GET")) fisier = st.nextToken(); dis.readLine(); } catch(IOException e) { System.out.println("Comanda incorecta"); } int c; try { FileInputStream f = new FileInputStream(fisier); while( (c=f.read()) != -1) os.write(c); f.close(); cs.close(); dis.close(); os.close(); } catch(IOException e) { System.out.println("Fisier inexistent"); }

} }

==============================

Exemplul 6. Dorim s folosim un calculator aflat la distan pentru a efectua anumite calcule asupra unor date din programul n curs de executare pe calculatorul local. ntruct scopul este de a pune n eviden mecanismul folosit i nu calculele n sine, vom reduce problema la a transmite la distan dou tablouri numerice de aceeai lungime i de a primi ca rezultat suma celor dou tablouri. Pentru transmiterea tablourilor, vom apela la mecanismul de serializare.

Clasa Tablou, ce implementeaz interfaa Serializable, trebuie s se afle att pe calculatorul local (pe post de client), ct i pe cel aflat la distan (folosit ca server).
// Unitatea de compilare Tablou.java import java.io.*; public class Tablou implements Serializable { private int[] t; Tablou(int[] tt) { t = tt; } public int[] out() { return t; } }

Clientul creeaz dou tablouri de ntregi i un socket prin care se leag la server. Fluxurile de intrare/ieire sunt nzestrate, prin suprapunere, cu facilitile oferite de clasele ObjectInputStream i ObjectOutputStream. Cele dou tablouri sunt serializate i transmise serverului. n fluxul de intrare va fi primit rezultatul: suma celor dou tablouri. Acest rezultat este deserializat i tiprit la ieirea standard:
// Unitatea de compilare AdunaClient.java import java.io.*; import java.net.*; public class AdunaClient { public static void main(String[] args) throws Exception { int[] a = {1,2,3,4}; int[] b = {4,3,2,1}; int[] c = new int[10]; int i; Socket cs = new Socket("localhost",5555); System.out.println("S-a legat"); InputStream is = null; OutputStream os = null; is=cs.getInputStream(); os=cs.getOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(os); ObjectInputStream ois = new ObjectInputStream(is); Tablou x = new Tablou(a), y = new Tablou(b), z = null; oos.writeObject(x); System.out.print("Transmis: "); for (i=0; i<a.length; i++) System.out.print(a[i]+" "); System.out.println(); oos.writeObject(y); System.out.print("Transmis: "); for (i=0; i<b.length; i++) System.out.print(b[i]+" "); System.out.println(); z = (Tablou) ois.readObject(); c = z.out(); System.out.print("Rezultat receptionat: "); for (i=0; i<c.length; i++) System.out.print(c[i]+" "); System.out.println(); ois.close(); oos.close(); cs.close();

} }

Complementar, serverul primete cele dou obiecte, obine din ele tablourile respective, le adun, asociaz rezultatului un obiect de tipul Tablou i transmite acest obiect clientului:
// Unitatea de compilare AdunaServer.java import java.io.*;

import java.net.*; public class AdunaServer { public static void main(String args[]) throws Exception { ServerSocket ss = null; Socket cs = null; InputStream is = null; OutputStream os = null; ss = new ServerSocket(5555); cs = ss.accept(); System.out.println("Clientul s-a conectat"); is=cs.getInputStream(); os=cs.getOutputStream(); ObjectInputStream ois = new ObjectInputStream(is); ObjectOutputStream oos = new ObjectOutputStream(os); Tablou x = null, y = null, z = null;; int[] a,b,c; int i; x = (Tablou) ois.readObject(); a = x.out(); y = (Tablou) ois.readObject(); b = y.out(); System.out.print("Receptionat: "); for (i=0; i<a.length; i++) System.out.print(a[i]+" "); System.out.println(); System.out.print("Receptionat: "); for (i=0; i<b.length; i++) System.out.print(b[i]+" "); System.out.println(); c = new int[a.length]; for (i=0; i<a.length; i++) c[i]=a[i]+b[i]; System.out.print("Rezultat transmis: "); for (i=0; i<c.length; i++) System.out.print(c[i]+" "); z = new Tablou(c); oos.writeObject(z); oos.flush(); ois.close(); oos.close(); cs.close(); ss.close(); } }

S-ar putea să vă placă și