PROGRAMAREA APLICATIILOR DE RETEA
La nivelul transport, internetul are doua protocoale principale: User Datagram Protocol (UDP, neorientat - conexiune) si Transmission Control Protocol (TCP, orientat - conexiune).
UDP este un protocol simplu, care nu asigura verificarea erorilor sau controlul fluxului, astfel fiind necesar ca aplicatia sa efectueze aceste verificari; se foloseste cu precadere la streaming multimedia. TCP este un protocol care asigura corectitudinea datelor, efectuand atat verificarea erorilor cat si controlul fluxului; este protocolul de baza pentru transmiterea informatiilor in retea .
In aceasta lucrare am exemplificat modul de functionare al celor doua protocoale prin intermediul unor aplicatii client-server. In cazul aplicatiei bazat 252g63c 9; pe protocolul UDP, serverul asculta un anumit port, iar daca o statie (un client) din retea trimite o cerere pe acel port, ea este prelucrata de server, rezultatul fiind apoi trimis catre client. In cazul aplicatiei bazat 252g63c 9; pe protocolul TCP, serverul asculta de asemenea un anumit port, dar la aparitia unei cereri este realizata mai intai o conexiune intre client si server; dupa stabilirea acesteia se realizeaza transferul de date.
Cel mai intalnit model de programare a aplicatiilor de retea poarta numele si de aplicatii Client-Server. Conceptul este simplu: o masina client face o cerere pentru o informatie sau trimite o comanda la un server; ca raspuns, serverul trimite datele cerute sau rezultatul comenzii. De cele mai multe ori, serverul raspunde numai la clienti; nu initiaza comunicatiile.
Asadar, functia serverului este de asculta pentru o conexiune. Aceste lucru este realizat printr-un obiect server care a fost special creat. Functia clientului este de a incerca sa stabileasca o conexiune cu serverul pentru care este creat un obiect client. Odata stabilita conexiunea, se poate observa ca la cele doua capete (server si client), conexiunea este transformata intr-un obiect IO Stream si din acel moment aceasta poate fi tratata ca si cum s-ar scrie sau s-ar citi dintr-un fisier.
Socket-ul este o abstractizare software pentru a reprezenta „capetele” unei conexiuni care se stabileste intre doua masini sau procese. Pentru o conexiune data, exista un socket pe fiecare masina si va puteti imagina un „cablu” ipotetic intre cele doua masini, fiecare capat al cablului fiind introdus intr-un socket.
In Java, este nevoie de crearea unui socket pentru a realiza conexiunea cu cealalta masina. Ulterior, se obtine InputStream-ul si OutputStream-ul de la socket pentru a putea trata conexiunea ca pe un obiect IOStream. Exista doua stream-uri folosite in clasele socket si sunt incluse in pachetul java.net. Acestea sunt java.net.ServerSocket (pe care server-ul in foloseste pentru „a asculta” pentru conexiuni noi ) si java.net.Socket (pe care clientul o foloseste pentru a initializa o conexiune). Odata ce clientul realizeaza o conexiune Socket, ServerSocket-ul returneaza un socket corespunzator server-ului prin care se realizeaza comunicarea.
Cand se creeaza un ServerSocket, ii dam doar numarul portului. Nu este nevoie sa se specifice adresa Ip deoarece este deja pe masina pe care o reprezinta. Totusi, atunci cand se creeaza un Socket, trebuie data adresa IP si numele portului la ce se incearca conectarea.
Clasele de socket-uri
Socket
ServerSocket
DatagramSocket
& Socket
Este obiectul Java care reprezinta conexiunea TCP. Cand se creeaza un socket, o conexiune pentru acea destinatie este deschisa.
Cele mai importante doua metode sunt getInputStream() si getOutputStream care returneaza obiecte stream care pot fi folosite pentru a comunica prin socket. Metodele sunt folosite si pentru a recupera informatii despre local host si numerele de porturi remote.
& ServerSocket
Reprezinta o conexiune TCP care „asculta”. Odata ce apare o cerere de conectare, obiectul ServerSocket returneaza un obiect Socket reprezentand conexiunea.
& DatagramSocket
Reprezinta un socket neorientat conexiune si este folosit in comunicatiile ce utilizeaza protocolul UDP.
Cele mai importante doua metode sunt: send() si receive(). Prima metoda trimite pachetul la o anumita gazda pe un anumit port. Metoda receive() blocheaza executia pana cand pachetul este primit de socket.
Setul de protocoale Internet suporta un protocol de transport fara conexiune, UDP (User Datagram Protocol – Protocol cu Datagrame Utilizator). UDP ofera aplicatiilor o modalitate de a trimite datagrame IP incapsulate si de a transmite fara a fi nevoie sa se stabileasca o conexiune. Este un protocol standard definit de STD numarul 6 si este descris de catre RFC 768 – User Datagram Protocol.
UDP este, in principiu, o aplicatie simpla de interfatare a IP. Nu adauga fiabilitate, controlul fluxului sau controlul erorilor. Asadar serviciile oferite de UDP sunt unreliable (fiabilitate scazuta), ceea ce inseamna ca nu garanteaza livrarea datelor sau protejarea de duplicate. Aceasta simplitate a protocolului determina un overhead redus, care poate fi avantajos in unele aplicatii care transmit unitati mici de date sau cele care permit pierderea unor cantitati mici de date (precum multimedia streaming).
Protocolul este folosit pur si simplu ca drept un multiplexor/demultiplexor pentru transmiterea si receptionarea datagramelor, folosind porturile pentru directionarea datagramelor.
UDP ofera mecanisme pentru ca o aplicatie sa trimita datagrame unei alte aplicatii. Nivelul UDP poate fi privit ca fiind extrem de slab si in consecinta, foarte eficient, dar necesita ca aplicatia sa fie cea care sa realizeze controlul erorilor, al fluxului etc.
Aplicatiile ce trimit datagrame unei statii trebuie sa identifice receptorul , care este mult mai specific decat adresa IP, deoarece datagramele sunt, de obicei, directionate spre procese specifice si nu catre intregul sistem. UDP realizeaza aceasta prin folosirea porturilor.
Aplicatiile care folosesc UDP au implementate, daca au nevoie, mecanisme pentru realizarea controlului erorilor, controlul fluxului, re-ordonarea datagramelor receptionate etc.
Un domeniu unde UDP este in mod special util este acela al situatiilor client-server. Deseori clientul trimite o cerinta scurta catre server si asteapta inapoi un raspuns scurt. Daca se pierde ori raspunsul, ori cererea, clientul poate pur si simplu sa incerce din nou dupa ce a expirat timpul. Nu numai ca ar fi mult mai simplu codul, dar sunt necesare si mai putine mesaje (cate unul in fiecare directie) decat la un protocol care solicita initializare.
O aplicatie care foloseste UDP in acest sens este DNS (Domain Name Server), un program care trebuie sa caute adresele IP ale unor nume gazda, de exemplu www.ce.berkeley.edu, poate trimite un pachet UDP, continand numele gazda, catre un server DNS. Serverul raspunde cu un pachet UDP ce contine adresa IP a gazdei. Nu este necesara nici o initializare in avans si nici o inchidere a sesiunii, doar doua mesaje traverseaza reteaua.
Pentru implementare am folosit urmatoarele clase si metode:
Clase
a. java.net.DatagramSocket – este o conexiune la un port care realizeaza transmiterea si receptarea datagramelor oricand; un DatagramSocket poate trimite la mai multe adrese diferite; adresa catre care se transmit datele este stocata in pachet, nu in socket
o transmitere – DatagramSocket()
o receptionare – DatagramSocket(int port)
!!! De remarcat ca nu se face distinctie intre un socket al clientului si cel al serverului (sunt de acelasi tip, nu precum la TCP)
b. java.net.DatagramPacket – folosit pentru datele de transmis (payload-ul), contine adresa si portul catre care se va transmite pachetul
o transmitere – DatagramPacket(byte[] data, int length, InetAddress host, int port)
o receptare – DatagramPacket(byte[] data, int length)
o dupa ce am construit pachetul putem folosi metodele clasei
Metode
DatagramSocket pentru a transmite si respectiv pentru a receptiona, astfel:
i. DatagramSocket.receive(DatagramPacket) – receptioneaza un DatagramPacket de la acest socket, aceasta metoda incarca buffer-ul lui DatagramPacket cu datele receptionate. DatagramPacket contine adresa IP si numarul portului emitatorului
ii. DatagramSocket.send(DatagramPacket) – transmite un DatagramPacket de la acest socket, aceasta metoda incarca in buffer-ul lui DatagramPacket datele receptionate. DatagramPacket contine adresa IP si numarul portului emitatorului
DatagramPacket
i. byte[] getData() – returneaza buffer-ul de date
ii. void setData(byte[] buf) – seteaza buffer-ul de date ca fiind cel curent
iii. void setAddress(InetAddress a)
iv. vi. InetAddress getAddress() – returneaza adresa IP a statiei catre care datagrama curenta este transmisa sau de la care este receptionata
v. void setPort(int port) – setarea numarului portului catre care se realizeaza transmiterea datagramei
vi. int getPort() – returneaza numarul portului statiei catre care se realizeaza transmiterea datagramei sau de la care s-a receptionat datagrama
Figura
Clientul
Creeaza un socket pentru a transmite datagrama
Transmite datele folosind socketul creat
Citeste raspunsul serverului
Inchide socketul creat
Figura
In continuare este prezentat un exemplu de Client UDP.
import java.io.*;
Creare stream de intrare
import java.net.*;
class UDPClient
}
Serverul
Creeaza un socket pentru primirea „cererilor”
Primeste datagrama de la client
Raspunde cererii primite
Asteapta conectarea unui nou client
In cele ce urmeaza este prezentat un exemplu de server UDP.
import java.io.*;
Creare socket la portul 9876
import java.net.*;
Creare spatiu pentru Datagrama primita Primire datagrama
class UDPServer
}
Desi protocolul TCP poate fi implementat ca sa lucreze peste orice protocol de transport, este de obicei asociat cu IP-ul.
TCP este un protocol orientat conexiune (ca un apel telefonic). Comunicatiile TCP se realizeaza folosind un proces asemanator cu stransul mainilor, unde fiecare informatie trimisa este confirmata de catre destinatar intr-un anumit interval de timp specificat de TCP.
TCP-ul ofera mai multe servicii cum ar fi siguranta corectitudinii datelor, verificarea erorilor si controlul fluxului. Daca un pachet este alterat sau pierdut (nu a fost confirmat), TCP retransmite informatiile de la client in mod automat.
Din cauza ca rutele pe care poate merge un pachet pot fi foarte multe, un pachet poate ajunge inaintea altui pachet transmis anterior. Pe parcursul primirii pachetelor este datoria TCP-ului sa asambleze pachetele in ordinea corecta. Acest lucru este aratat mai jos in FIGURA care contine o topologie de retea in care pachetele de retea trec prin n hopuri pentru a ajunge de la sursa la destinatie. Intr-o retea mare cum este Internetul, exista foarte multe rute prin care pachetele pot trece pentru a ajunge la destinatie.
Figura
Aplicatii aflate pe hosturi din retea pot crea conexiuni intre ele folosind TCP, si pot schimba fluxuri de date folosind socket-uri. TCP face o diferentiere a datelor pentru a putea exista multiple conexiuni ale aplicatiilor concurente (ex: server web si de e-mail) ce ruleaza pe acelasi host.
In cazul protocoalelor de Internet, TCP este planul intermediar intre IP (Internet Protocol) care se afla inferior si aplicatia ce se afla superior. Programele au deseori nevoie de conexiuni sigure si IP-ul nu asigura aceste necesitati. TCP-ul indeplineste rolul de transport in modelul OSI de retea.
Aplicatiile trimit stream-uri de octeti catre TCP pentru transmitere, iar acesta le divide in segmente de dimensiuni mai mici decat maximul admis. TCP trimite apoi pachetele rezultate catre IP pentru retrimiterea catre modulul TCP de la celalalt capat. Protocolol asigura ca nici un pachet nu se pierde prin atasarea fiecaruia a unui identificator, care este folosit deasemenea pentru a se asigura primirea in ordine. Modulul TCP de la celalalt capat trimite un mesaj de validare (acknowledgment) pentru pachetele primite cu succes.
Pentru implementare am folosit urmatoarele clase si metode:
a. java.net.Socket
o public Socket(String host, int port) throws
UnknownHostException,IOException
P constructor care deschide o conexiune
TCP catre host-ul si portul specificati ca parametri.
o public Socket(InetAddress host, int port) throws
UnknownHostException,IOException
P constructor care deschide o conexiune
TCP catre host-ul si portul specificati ca parametri.
o public OutputStream getOutputStream()
P intoarce fluxul de iesire pentru
socket.
o public InputStream getInputStream()
P intoarce fluxul de intrare pentru
socket.
o public void close()
P inchide socket-ul.
b. java.net.ServerSocket
o public ServerSocket(int port) throws IOException,BindException
P constructor care inregistreaza serverul la portul specificat ca parametru.
o public Socket accept()
P asculta cererile de conexiuni, intoarce un obiect
Socket care va fi utilizat pentru comunicarea cu clientul.
Figura
Clientul
Se deschide un socket TCP catre server
a. Se creeaza o instanta a clasei Socket
b. Se deschide un flux de iesire pentru a scrie la socket prin instantierea unui obiect
c. Se deschide un flux de intrare pentru a citi de la socket prin instantierea unui obiect
Mesajul catre server este formatat
Se trimite un mesaj la server
Se citeste raspunsul serverului
Se inchide socket-ul
In continuare este prezentat un exemplu de Client TCP.
import java.io.*;
import java.net.*;
class TCPClient
Serverul
Se deschide un socket TCP pentru ascultarea cererilor de conexiuni
a. Se creeaza o instanta a clasei ServerSocket
Asteapta ca un client sa se conecteze si creaza un nou socket pentru a realiza comunicarea
a. Se foloseste metoda accept a clasei ServerSocket
b. Se deschide un flux de iesire pentru a scrie in socket, prin instantierea unui obiect DataOutputStream
c. Se deschide un flux de intrare pentru a citi de la socket prin instantierea unui obiect BufferedReader
Se citeste raspunsul clientului
Se proceseaza raspunsul clientului
Se trimite un mesaj catre client
Se inchide socket-ul
Se asteapta alt client
In cele ce urmeaza este prezentat un exemplu de server TCP.
import java.io.*;
import java.net.*;
class TCPServer
}
In ultimul deceniu, arhitectura client/server a ajuns cel mai cunoscut model pentru aplicatiile de retea. Astazi, multe dintre aplicatiile cu care suntem familiarizati sunt client/server: Web-ul, e-mail, ftp, telnet, si asa mai departe.
Acest articol prezinta principiile de baza ale programarii client/server si modul in care Java suporta aceasta arhitectura. Primul pas a fost de a intelege modul de lucru cu elementele de baza ale programarii client server: socket-urile. Insa aplicatiile prezentate pot servi ca modele de implementari software pentru realizarea altor aplicatii de retea mult mai avansate, folosind fie protocolul UDP, fie TCP, in functie de destinatia aplicatiei.
- BSD Sockets Programming from a Multi-Language Perspective, Charles River Media, 2004 https://www.calsoftlabs.com/
https://www.linuxjournal.com/ article/2333
https://beej.us/guide/bgnet/
https://docsrv.sco.com/
https://www.frostbytes.com/
|