450 likes | 551 Views
Comunicatie punct-la-punct (client-server, instanta-instanta). Mugurel Ionu ț Andreica 2012. Nivelul transport al stivei OSI. Application Presentation Session Transport Conexiuni punct-la-punct Fiabilitate Controlul congestiei Protocoalele cele mai populare: UDP, TCP Network
E N D
Comunicatie punct-la-punct(client-server,instanta-instanta) Mugurel Ionuț Andreica 2012
Nivelul transport al stivei OSI • Application • Presentation • Session • Transport • Conexiuni punct-la-punct • Fiabilitate • Controlul congestiei • Protocoalele cele mai populare: UDP, TCP • Network • Data link • Physical
Protocolul UDP • Nu este orientat pe conexiune • Un mesaj transmis ajunge la destinatie in aceeasi forma sub care a fost transmis sau nu ajunge deloc • Nu se garanteaza transmisia mesajului • Nu se asigura controlul congestiei retelei
Protocolul TCP • Orientat pe conexiune • Transmite fluxuri de bytes • Chiar daca aplicatia transmite mesaje, limitele mesajelor nu sunt pastrate de TCP (continutul unui mesaj este pur si simplu adaugat in continuare la fluxul de bytes) • Garanteaza transmisia datelor • Asigura controlul congestiei (utilizeaza o fereastra de congestie)
Probleme UDP, TCP • UDP • Nu garanteaza transmisia mesajelor • Nu asigura controlul congestiei • TCP • nu poate folosi eficient conexiuni cu latime de banda mare si latenta mare (adica viteza de transfer a datelor poate fi departe de viteza maxima posibila) • Head-of-line blocking • interconectarea nodurilor din spatele unui NAT sau firewall
Algoritmul de control al congestiei utilizat de TCP (AIMD) • Additive increase / multiplicative decrease • w = w + 1/w, la fiecare ACK primit • w = 0.5 * w, la fiecare pachet pierdut • conexiune de 10 Gbps, latenta de 100ms, segment de 1500 bytes, rata de transfer de 10 Gbps 1 pachet pierdut la 1h 40’ + o fereastra de congestie de 83,333 segmente
Comunicatia punct-la-punct de tip client-server • In cazul multor servicii, datele transmise de la client la server (si inapoi) au dimensiuni reduse (in acest caz, se poate utiliza cu succes TCP si chiar UDP, daca nu este necesara o garantie ca cererea ajunge la server si ca raspunsul ajunge inapoi la client) • Exista si exceptii, in cazul serviciilor data-intensive • FTP: clientul cere un fisier si primeste ca raspuns fisierul, care poate fi foarte mare • Youtube: clientul cere un clip video, iar server-ul i-l trimite; clip-ul poate fi consumat de client pe masura ce il primeste • Flickr: clientul upload-eaza un director intreg cu poze • Content distribution platform (P2P-Next): serviciul distribuie continutul creat de client (de ex., un stream live generat de client este distribuit altor clienti prin intermediul serviciului)
Comunicatia punct-la-punct de tip instanta-instanta • Instantele serviciului au nevoie, uneori, sa transfere date intre ele, de ex.: • Pentru actualizarea si mentinerea starii interne a serviciului • In cazul unui serviciu de distributie de continut: • Un client cere unei instante un element de continut (fisier, clip video, stream live, etc.), pe care instanta nu-l detine ; aceasta contacteaza alta instanta, pentru a transfera elementul de continut cerut de client si a-l oferi apoi clientului (comportament reactiv) • O instanta transmite un element de continut (de ex., fisier) unei alte instante in mod proactiv, pentru ca aceasta sa-l aiba la dispozitie si sa-l poata servi imediat clientilor sai
Alternative pentru UDP/TCP (1/2) • Alternative la nivelul transport • Protocoale bazate pe TCP standard • HighSpeed TCP • Scalable TCP • FAST TCP • CUBIC • Alte protocoale de transport • SCTP
Alternative pentru UDP/TCP (2/2) • Alternative la nivel aplicatie • Protocoale de transport bazate pe UDP(+TCP) • RBUDP • UDT • SABUL • Conexiuni TCP paralele multiple • PSockets • GridFTP
HighSpeed TCP • algoritmul de control al congestiei • daca w < wmax, foloseste algoritmul TCP standard • altfel • w = w + a(w)/w, la fiecare ACK primit • w = (1-b(w))*w, la fiecare pachet pierdut • conexiune de 10 Gbps, latenta de 100ms, rata de transfer de 10 Gbps 1 pachet pierdut la 12 sec • comportament “corect” fata de fluxuri TCP standard pe conexiuni obisnuite numai cand procentul de pachete pierdute e mare
Scalable TCP • algoritmul de control al congestiei • daca w < wmax, foloseste algoritmul TCP standard • altfel • w = w + 0.01, la fiecare ACK primit • w = 0.875*w, la fiecare pachet pierdut • comportament “corect” fata de fluxuri TCP standard pe conexiuni obisnuite
FAST TCP • algoritmul de control al congestiei – 3 faze: • slow start – TCP standard • multiplicative increase – aduce repede o conexiune FAST TCP aproape de echilibru • Exponential convergence – un fel de cautare binara • w_nou = 0.5 * (w_vechi * RTT/RTT_mediu + alpha + w_curent) • comportament “corect” fata de fluxuri TCP standard pe conexiuni obisnuite
TCP CUBIC • algoritmul de control al congestiei • W = C * (t-K)3 + Wmax • Wmax = estimare dinamica a valorii maxime • K = (Wmax * beta / C)1/3 • t = durata de timp de la ultimul pachet pierdut (la t=0, W=(1-beta)*Wmax) • stabilitate crescuta • comportament “corect” fata de fluxuri TCP standard pe conexiuni obisnuite
SCTP (1/2) • Protocol de nivel transport • “Conexiunea” se numeste asociatie (in terminologia SCTP) • O asociatie poate avea mai multe stream-uri independente • Fiecare stream are un algoritm de control al congestiei similar TCP-ului • O asociatie SCTP cu N stream-uri este aproximativ echivalenta cu N conexiuni TCP paralele, dar cantitatea de resurse consumate este mai mica (de ex., mai putini file descriptori utilizati, etc.)
SCTP (2/2) • Pastreaza limitele mesajelor (fiecare mesaj trimis este primit separat de celelalte) • Daca exista pierderi de pachete pe un stream, acestea nu afecteaza celelalte stream-uri • Multihoming: permite ca cele doua capete ale asociatiei sai aiba mai multe adrese IP (pentru redundanta) • Extensii pentru transfer multi-path (fiecare adresa IP a unui capat poate corespunde unui drum diferit prin retea)
RBUDP • mai multe faze de transmisie a pachetelor • trimite pachete UDP cu o rata R • anunta prin TCP sfarsitul transmisiei; primeste inapoi un sir de biti reprezentand pachetele receptionate cu succes • retransmite pachetele pierdute si incepe faza urmatoare • daca rata pachetelor pierdute (lossRate) > 0 => R = R * (0.95 – lossRate)
UDT • numere de secventa pentru pachete si ACK-uri • 1 ACK la fiecare 0.01 sec (selective acknowledgement) • NAK • timer pentru controlul ratei de transmisie – recalculare a ratei pe baza procentului de pachete pierdute • estimare a capacitatii conexiunii (folosind metoda perechii de pachete) • fereastra pentru controlul congestiei (calculata folosind rata de sosire a pachetelor)
SABUL • “conexiune de date” folosind UDP • conexiune de control folosind TCP • ACK • NAK • numere de secventa + limitare la MTU pt pachetele de date • se calculeaza periodic o medie exponentiala a ratei de pierderi =>se modifica rata de transmisie
datele sunt transmise pe mai multe conexiuni TCP deschise in paralel catre aceeasi destinatie API similar cu Berkeley sockets PSockets Rata de transfer (Mb/s) Numarul de socket-i
GridFTP • extensie a protocolului FTP • securitate • conexiuni TCP paralele • buffer-e TCP adaptate in functie de transmitator-receptor • multipunct-la-multipunct • API similar cu POSIX
Solutii fezabile pentru dezvoltarea de servicii • Protocoale implementate in majoritatea sistemelor de operare • TCP, UDP (Linux, Windows, etc.) • SCTP (Linux, Solaris, etc. – nu si pe Windows, inca) • Utilizare prin intermediul API-ului standard pentru sockets • Variantele de TCP sunt greu de utilizat, deoarece nu exista suport in kernel-ul sistemelor de operare pentru ele • Protocoalele implementate in user-space necesita utilizarea unor biblioteci speciale, care trebuie instalate si pe masina clientului (care implementeaza API-ul) • Conexiuni TCP paralele: • TCP este implementat in toate sistemele de operare • Codul sursa pentru managementul comunicatiei devine mai complex, deoarece trebuie gestionate explicate conexiunile paralele TCP (mai ales cele care transfera date din acelasi fisier / element de continut)
Socket API • bine cunoscut si standardizat • (foarte) multe aplicatii il utilizeaza • toate bibliotecile de comunicatie de nivel (mai) inalt folosesc dedesubt sockets • Nu exprima foarte bine necesitatile de comunicatie client-server • Ne-am dori ceva gen RPC (cerere-raspuns), nu fluxuri de bytes sau mesaje independente • socket() • bind() • listen() • accept() • connect() • send() • recv()
TCP Sockets in Java (1/3) import java.net.*; import java.io.*; ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.err.println("Could not listen on port: 4444."); }
TCP Sockets in Java (2/3) Socket clientSocket = null; try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed."); } PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); out.println(“from server”); BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String inputLine = in.readLine(); System.out.println(inputLine); out.close(); in.close(); clientSocket.close(); serverSocket.close();
TCP Sockets (3/3) Socket clientSocket = new Socket(“fep.grid.pub.ro", 4444); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader( clientSocket.getInputStream())); String inputLine = in.readLine(); System.out.println(inputLine); out.println(“from client”); out.close(); in.close(); clientSocket.close();
UDP Sockets in Java (1/2) DatagramSocket socket = new DatagramSocket(4445); byte[] buf = new byte[256]; // receive request DatagramPacket packet = new DatagramPacket(buf, buf.length); socket.receive(packet); // send the response to the client at "address" and "port“ InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(buf, 0, buf.length, address, port); socket.send(packet); socket.close()
UDP Sockets in Java (2/2) // get a datagram socket DatagramSocket socket = new DatagramSocket(); // send request byte[] buf = new byte[256]; InetAddress address = InetAddress.getByName(“fep.grid.pub.ro”); DatagramPacket packet = new DatagramPacket(buf, 0, buf.length, address, 4445); socket.send(packet); // get response packet = new DatagramPacket(buf, buf.length); socket.receive(packet); // display response String received = new String(packet.getData(), 0, packet.getLength()); System.out.println(“Received data: " + received); socket.close();
Java NIO (I/O asincron) (1/3) • clasele Selector, SocketChannel, ServerSocketChannel, SelectionKey, etc.
Java NIO (I/O asincron) (2/3) • Evenimente de I/O • Sunt date disponibile pentru a fi citite de pe un socket (TCP, UDP) • Exista spatiu in buffer-ul unui socket pentru a scrie date noi (TCP, UDP) • Exista cereri de initiere de conexiuni (care pot fi acceptate) (TCP) • S-a finalizat conectarea la server (TCP) • Un thread de control ce foloseste un obiect Selector
Java NIO (I/O asincron) (3/3) • Thread-ul executa urmatorul cod, intr-o bucla: • Asteapta sa se produca un eveniment interesant (care prezinta interes pentru aplicatie) • Proceseaza evenimentele care tocmai au avut loc • Proceseaza cereri de schimbare a operatiilor de interes pentru socketi sau cereri de inregistrare a unor noi socketi • Pentru a astepta evenimente asociate unui socket, acesta trebuie inregistrat la Selector pentru o multime de operatii care prezinta interes (read/write/accept/connect) • Multimea operatiilor care prezinta interes poate fi modificata dinamic (insa este de preferat ca aceste modificari sa fie efectuate tot de catre thread-ul Selector-ului) – de aceea se foloseste o coada cu cereri de schimbare a operatiilor de interes • Inregistrarea unui socket nou la Selector trebuie realizata tot de catre thread-ul Selectorului (de aceea se foloseste o coada cu astfel de cereri care este verificata de thread-ul Selector-ului)
Clasa ByteBuffer (Java NIO) • Utilizata pentru a scrie date / citi date pe / de pe socketi • Are un array de bytes intern • Metode pentru a adauga date in array-ul de bytes, pentru a sterge array-ul de bytes, pentru a-l trece din modul de scriere in cel de citire, etc.
Clasa SocketChannel (Java NIO) • configureBlocking(true / false) • register(selector, operatii de interes) • read(ByteBuffer buf) • Intoarce cati bytes au fost cititi efectiv • write(ByteBuffer buf) • Intoarce cati bytes au fost scrisi efectiv
Clasa ServerSocketChannel (Java NIO) • Aceleasi metode ca si SocketChannel • In plus: • bind : leaga socket-ul la un port pe care asculta cereri de conectare de la clienti • accept : accepta o conexiune • Intoarce un SocketChannel, prin care se va comunica cu clientul (sau null, daca nu exista cereri de conectare in asteptare din partea clientilor)
Selector (Java NIO) • select() • Asteapta evenimente pe socketii inregistrati la Selector (doar pentru tipurile de operatii care prezinta interes) • select(timeout) • Astapta pana cand ar eloc un eveniment de interes sau pana cand expira timeout-ul • wakeup() • Forteaza deblocarea Selector-ului din starea de asteptare (din functia select()) • keys() • Intoarce setul de chei (SelectionKey) ale socketilor inregistrate la Selector • selectedKeys() • Intoarce setul de chei selectate (pe care a avut loc un eveniment detectat in urma ultimului apel select())
SelectionKey (Java NIO) (1/2) • Cand se inregistreaza un SocketChannel (sau ServerSocketChannel) la Selector, acesta i se asociaza un SelectionKey • interestOps() – intoarce multimea de operatii de interes • Operatii posibile: OP_READ, OP_WRITE, OP_CONNECT, OP_ACCEPT • Reprezentare pe biti (cate 1 bit pentru fiecare operatie) • interestOps(X) – seteaza multimea de operatii de interes la valoarea X; de ex.: • key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE) : seteaza operatiile de interes ca fiind OP_READ si OP_WRITE • key.interestOps(key.interestOps() | SelectionKey.OP_READ) : adauga operatia OP_READ ca operatie de interes • key.interestOps(key.interestOps() ^ SelectionKey.OP_WRITE) : schimba starea de interes pentru operatia OP_WRITE (daca prezenta interes inainte, acum nu va mai prezenta interes ; sau invers)
SelectionKey (Java NIO) (2/2) • channel() : intoarce SocketChannel-ul asociat cheii (se poate face cast la ServerSocketChannel daca stim sigur ca are un ServerSocketChannel asociat) • isAcceptable() : intoarce true daca se poate apela accept cu succes pe ServerSocketChannel-ul asociat cheii • isReadable() : intoarce true daca sunt date ce pot fi citite de pe SocketChannel-ul asociat cheii • isWritable() : intoarce true daca este loc in buffer-ul socket-ului pentru a scrie date noi • isConnectable() : intoarce true daca se poate finaliza cu succes conectarea (TCP) la server • cancel() : cheia e deinregistrata de la Selector
Procesarea tuturor evenimentelor NIO in acelasi thread • Un server socket ramane mereu inregistrat cu OP_ACCEPT la Selector • Imediat ce se face accept(), noul SocketChannel e inregistrat cu OP_READ • Orice SocketChannel ramane inregistrat cu OP_READ la Selector intotdeauna (pana cand este inchis) • Cand se doreste scrierea de date pe un socket S (eventual dintr-un alt thread): • Se pun datele intr-un buffer asociat lui S • Se pune o cerere de schimbare a operatiilor de interes ale lui S in coada de cereri (se cere inregistrarea lui S pentru OP_WRITE) • Se face selector.wakeup() • Cand o cheie este writable: • Se scriu datele din buffer-ul asociat socket-ului S pe socket pana cand: • S-au scris toate datele => in acest caz se trimite o cerere de deinregistrare a lui S de la operatia OP_WRITE • Nu mai e loc in buffer-ul socket-ului (S ramane inregistrat pentru OP_WRITE, urmand ca urmatoarea data cand socket-ul e writable, sa se continue scrierea datelor)
Procesarea evenimentelor NIO dintr-un thread pool (1/4) • Pentru fiecare eveniment (read / write / accept / connect), thread-ul Selector-ului trimite un job unui pool de thread-uri • Practic, evenimentul va fi procesat de un thread din pool si nu de thread-ul Selector-ului (ca in varianta anterioara) • Inainte de a trimite job-ul, cheia de selectie e deinregistrata de la Selector pentru operatia care urmeaza a fi procesata (de ex., pentru un eveniment de read, se deinregistreaza operatia OP_READ)
Procesarea evenimentelor NIO dintr-un thread pool (2/4) • Procesare eveniment de accept: • Se accepta conexiunea • Se trimite cerere de inregistrare a SocketChannel-ului la Selector (nu se inregistreaza direct din thread-ul curent) • Se trimite cerere de reinregistrare a cheii de selectie pentru operatia OP_ACCEPT
Procesarea evenimentelor NIO dintr-un thread pool (3/4) • Procesare eveniment de read: • Se citesc datele de pe socket si se adauga intr-un buffer de citire (in continuare) • Daca s-au identificat cereri complete noi, acestea sunt trimise spre a fi procesate • Se trimite cerere pentru reinregistrarea cheii de selectie pentru operatia OP_READ
Procesarea evenimentelor NIO dintr-un thread pool (4/4) • Procesare eveniment de write: • Se scriu datele din buffer-ul de scriere pe socket (datele sunt puse in buffer la fel ca in cazul procesarii tuturor evenimentelor dintr-un singur thread, deoarece ele sunt adaugate acolo de alte thread-uri – cele care trimit rezultatul inapoi catre client) • Daca mai sunt date de scris (dar nu mai e loc in buffer-ul socket-ului) se trimite o cerere de reinregistrare a cheii de selectie pentru operatia OP_WRITE • Daca s-au scris toate datele, atunci nu se mai face nimic (cheia de selectie este deja deinregistrata de la operatia OP_WRITE)
SCTP Sockets in Java (1/2) • Trebuie instalat Open JDK 7 pentru a avea suport SCTP (doar pe Linux 2.6.28+) import java.io.*; import java.net.*; import java.nio.*; import com.sun.nio.sctp.*; SocketAddress serverSocketAddress = new InetSocketAddress(1111); System.out.println("create and bind for sctp address"); SctpServerChannel sctpServerChannel = SctpServerChannel.open().bind(serverSocketAddress); System.out.println("address bind process finished successfully"); SctpChannel sctpChannel; ByteBuffer buf = ByteBuffer.allocate(64000); while ((sctpChannel = sctpServerChannel.accept()) != null) { System.out.println("client connection received"); System.out.println("sctpChannel.getRemoteAddresses() = " + sctpChannel.getRemoteAddresses()); System.out.println("sctpChannel.association() = " + sctpChannel.association()); MessageInfo messageInfo = sctpChannel.receive(buf, null, null); System.out.println(messageInfo); sctpChannel.close(); } sctpServerChannel.close();
SCTP Sockets in Java (2/2) try { SocketAddress socketAddress = new InetSocketAddress(6050); System.out.println("open connection for socket [" + socketAddress + "]"); SctpChannel sctpChannel = SctpChannel.open(); sctpChannel.bind(new InetSocketAddress( 6060)); sctpChannel.connect(socketAddress, 4 ,3); // param 2: maxOutStreams ; param 3: maxInStreams System.out.println("sctpChannel.getRemoteAddresses() = " + sctpChannel.getRemoteAddresses()); System.out.println("sctpChannel.getAllLocalAddresses() = " + sctpChannel.getAllLocalAddresses()); System.out.println("sctpChannel.isConnectionPending() = " + sctpChannel.isConnectionPending()); System.out.println("sctpChannel.isOpen() = " + sctpChannel.isOpen()); System.out.println("sctpChannel.isRegistered() = " + sctpChannel.isRegistered()); System.out.println("sctpChannel.provider() = " + sctpChannel.provider()); System.out.println("sctpChannel.association() = " + sctpChannel.association()); System.out.println("send bytes"); ByteBuffer byteBuffer = ByteBuffer.allocate(64000); byte [] message = new byte []{1,0,3,1,0,0,0,24,0,17,0,8,0,0,0,1,0,4,0,8,84,101,115,116}; MessageInfo messageInfo = MessageInfo.createOutGoing(null, 0); // al 2-lea parametru e nr stream-ului System.out.println("messageInfo = " + messageInfo); System.out.println("messageInfo.streamNumber() = " + messageInfo.streamNumber()); byteBuffer.put(message); byteBuffer.flip(); sctpChannel.send(byteBuffer, messageInfo); System.out.println("close connection"); sctpChannel.close(); } catch (Exception e) {}
Link-uri utile • Mini-tutorial socketi TCP: http://download.oracle.com/javase/tutorial/networking/sockets/index.html • Mini-tutorial socketi UDP: http://download.oracle.com/javase/tutorial/networking/datagrams/index.html • Exemplu socketi SCTP: http://sandarenu.blogspot.com/2009/05/sctp-client-server-in-java.html • Open JDK 7: http://openjdk.java.net/projects/jdk7/ • Tutorial Java NIO: http://rox-xmlrpc.sourceforge.net/niotut/