Differences

This shows you the differences between two versions of the page.

Link to this comparison view

sde:laboratoare:10_ro_python [2020/04/21 17:38]
ioana_maria.culic [Exercițiul 3 - Comunicare TCP]
— (current)
Line 1: Line 1:
-====== Laborator 10 - Comunicarea prin rețea ====== 
- 
-===== Prezentare teoretică ===== 
- 
-Pentru a putea discuta despre comunicarea într-o rețea, este important să cunoaștem următoarele noțiuni: 
-  *[[#Adresa fizică|Adresa fizică]] 
-  *[[#Adresa IP|Adresa IP]] 
-  *[[#​Port|Port]] 
- 
-===== Adresa fizică ===== 
-Adresa fizică, numită și adresa MAC este un număr pe 48 de biți care identifică unic o placă de rețea. Acest număr este inscripționat în placa de rețea de către producător,​ deci, în general nu poate fi schimbat. Adresa MAC este folosită pentru transmisia de date la nivelul de access la rețea din stiva TCP/​IP. ​ 
- 
-O adresă MAC este reprezentată prin gruparea celor 48 de biți în câte 6 octeți și scrierea fiecărui octet in baza 16 (ex: 00:​A0:​C9:​14:​C8:​29 sau 00A0-C914-C829). 
-===== Adresa IP ===== 
-O adresă IP identifică o stație într-o rețea și se folosește pentru transmisia de date la nivelul rețea din stiva TCP/IP. 
- 
-Practic, IP-ul unei stații este un număr, pe 32 de biți în cazul protocolului IPv4 sau pe 128 de biți în cazul protocolului IPv6. Uzual, adresele IP sunt scrise sub forma restransă. În cazul IPv4, adresa IP este scrisă sub formă de 4 numere în baza zecimală, cu valori între 0 și 255, separate prin . (ex: 192.168.0.14),​ iar în cazul IPv6, adresa IP este scrisă sub formă de 8 grupuri numere în baza hexazecimală,​ cu valori cuprinse între 0000 și ffff, separate prin : (ex: 2001:​0db8:​85a3:​0000:​0000:​8a2e:​0370:​7334). ​ 
- 
-===== Port ===== 
-Portul este un identificator folosit pentru transmisia de date la nivelul aplicație. 
- 
-Pentru a asigura că două aplicații comunică prin rețea trebuie să specificăm adresa IP a stațiilor care comunică, dar și portul. În timp ce adresa IP asigură că pachetele ajung la destinație,​ portul asigură că pachetul primit este folosit de aplicația potrivită. 
- 
-De exemplu, două calculatoare pot să comunice atât pentru a face schimb de email-uri, dar și pentru a realiza o video-conferință. Astfel, cele două calculatoare fac schimb pe mesaje pentru ambele aplicații (email și video-conferință). În timp ce adresele IP sunt folosite pentru a ne asigura că toate pachetele ajung unde trebuie, aplicațiile de email și de video-conferintă vor avea atribuit câte un port diferit, pe baza căruia mesajele vor fi distribuite aplicației potrivite. 
- 
-<note info> 
-În aplicațiile dezvoltate de noi trebuie să ne asigurăm ca alegem o valoare pentru port care nu e folosită de alte aplicații existente pe sistem. Altfel, riscăm să obținem conflicte. De aceea alegem valoarile **8000** sau **8080**, care nu sunt folosite de servicii cunoscute. 
-</​note>​ 
-===== Socket ===== 
-Pentru a putea realiza transmisia de mesaje pe rețea, vom folosit structuri de tip socket. 
- 
-Un socket permite transmisia de mesaje între aplicații de pe aceeasi mașină sau de pe mașini fizice diferite, într-o manieră similară cu cea folosind file descriptori. 
- 
-În Python, vom folosi modulul [[https://​docs.python.org/​3/​library/​socket.html|socket]] pentru operațiile privind comunicarea prin rețea. Printre operațiile pe care le putem realiza folosind modulul ''​socket''​ se numără: 
-  * [[#​Obținerea de informații despre stația curentă|obținerea de informații despre stația curentă]]; 
-  * [[#​Obținerea de informații despre alte elemente din rețea|obținerea de informații despre alte elemente din rețea]]; 
-  * [[#Crearea de conexiuni TCP|crearea de conexiuni TCP]]; 
-  * [[#Schimbul de date pe rețea|schimbul de date pe rețea]]. 
- 
-==== Obținerea de informații despre stația curentă ==== 
-Funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.gethostname|gethostname]] returnează adresa IPv4 a stației locale. 
-<code python> 
-socket.gethostname() 
-</​code>​ 
- 
-====Obținerea de informații despre alte elemente din rețea==== 
-Funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.getaddrinfo|getaddrinfo]] întoarce o listă cu 5 elemente care conțin informații despre o adresă și un port specificat. Lista returnată conține următoarele informații:​ ''​(family,​ type, proto, canonname, sockaddr)'',​ iar ''​sockaddr''​ e o altă listă ce conține ''​(address,​ port)''​. 
-<code python> 
-socket.getaddrinfo(host,​ port, family=0, type=0, proto=0, flags=0) 
-</​code>​ 
- 
-Funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.gethostbyname|gethostbyname]] returnează adresa IPv4 a unui ''​hostname''​. 
-<code python> 
-socket.gethostbyname(hostname) 
-</​code>​ 
- 
-====Crearea de conexiuni TCP==== 
-Folosind sockeți putem realiza două tipuri de transmisii de date: UDP sau TCP. 
- 
-Pentru oricare din cele două tipuri de transmisii, trebuie să creăm un obiect nou de tip ''​socket''​ folosind funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket|socket (family=AF_INET,​ type=SOCK_STREAM,​ proto=0, fileno=None)]]. 
-În funcție de parametrii pasați constructorului,​ socket-ul este configurat pentru un anumit tip de transfer de date. 
- 
-  * family - reprezintă tipul de adresare folosit (ex: pentru IPv4, tipul folosit este ''​AF_INET'',​ pentru IPv6 tipul este ''​AF_INET6''​);​ în cazul nostru, vom folosi AF_INET (socket.AF_INET,​ în Python); 
-  * type - reprezintă tipul de transfer de date folosit; în general, vom alege între ''​SOCK_STREAM''​ (pentru transferul TCP) și ''​SOCK_DGRAM''​ (pentru transferul UDP); 
-  * proto - reprezintă protocolul folosit, în cazul nostru vom lăsa valoarea prestabilită;​ 
-  * fileno - reprezintă un ''​file descriptor'',​ iar dacă acest parametru este pasat, toate celelalte 3 valori sunt stabilite automat pe baza acestuia. 
- 
-<code python> 
-import socket 
-s = socket.socket() 
-</​code>​ 
- 
-Pentru transferul de tip TCP, se folosește paradigma client-server,​ în care un proces așteaptă conexiuni (server), în timp ce alte procese se pot conecta la acesta (client). Folosind TCP datele transmise ajung cu siguranță la destinație sau se primește o eroare. 
- 
-===Inițializarea serverului=== 
-Pentru a porni un server folosind modului ''​socket'',​ trebuie să efectăm următoarele operații: 
-  * Să atribuim o adresă și un port socket-ului ([[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.bind|bind]]) 
-  * Să specificăm că așteptăm conexiuni și câte ([[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.listen|listen]]) 
-  * Să acceptăm conexiunile primite ([[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.accept|accept]]);​ funcția întoarce un tuplu cu două valori: conexiunea și o adresă; conexiunea este o variabilă de tip ''​socket'',​ care va fi folosită pentru transmisia de mesaje; adresa este adresa programului care s-a conectat. 
- 
-<note info> 
-Dacă adresa IP pasată funcției ''​bind''​ este ''​0.0.0.0'',​ socket-ul acceptă conexiuni de pe toate plăcile de rețea. 
-</​note>​ 
-==Exemplu== 
-<code python> 
-import socket 
-s = socket.socket() 
-s.bind(('​0.0.0.0',​ 8000)) 
-s.listen(0) 
-conn, addr = serv.accept() 
-</​code>​ 
- 
-===Inițializarea clientului=== 
-Pentru a iniția o conexiune din partea serverului, folosind modului ''​socket'',​ trebuie să apelăm funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.connect|connect]]. 
- 
-Pentru a încheia conexiunea cu serverul, vom folosi funcția [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.close|close]]. 
-==Exemplu== 
-<code python> 
-import socket 
-s = socket.socket() 
-s.connect(('​localhost',​ 8000)) 
-# send/​receive data 
-s.close() 
-</​code>​ 
- 
-<note info> 
-Pentru a ne conecta la un serviciu ce rulează pe mașina locală, putem folosi adresa ''​localhost''​ sau ''​127.0.0.1''​. 
-</​note>​ 
- 
-====Schimbul de date pe rețea==== 
-===Trimiterea de date=== 
-Pentru a trimite date folosind modulul ''​socket''​ putem folosi funcțiile [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.send|send]] și [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.sendto|sendto]]. 
-<code python> 
-socket.send(bytes[,​ flags]) 
-socket.sendto(bytes,​ address) 
-socket.sendto(bytes,​ flags, address) 
-</​code>​ 
- 
-Funcția ''​send''​ trimite date doar dacă socket-ul este conectat la un alt socket, deci poate fi folosită doar pentru o transmisie de tip TCP. 
- 
-Funcția ''​sendto''​ trimite date la o adresă pasată ca parametru, fără a necesita o conexiune stabilită între cele două obiecte socket, deci poate fi folosită pentru o transmisie de tip UDP.  
-<note info> 
-Parametrul ''​address''​ este un tupul de tipul (adress, port), ex: ("​0.0.0.0",​ 8000). 
-</​note> ​ 
- 
-===Primirea de date=== 
-Pentru a primi date folosind modulul ''​socket''​ putem folosi funcțiile [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.recv|recv]] și [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.recvfrom|recvfrom]]. 
-<code python> 
-socket.recv(bufsize[,​ flags]) 
-socket.recvfrom(bufsize[,​ flags]) 
-</​code>​ 
- 
-Funcția ''​recv''​ citește date până la dimensiunea maximă, specificată ca parametru (''​bufzise''​) și le returnează sub forma unui obiect de tip ''​bytes''​. Această funcție este potrivită pentru transmiterea de tip TCP, unde avem o conexiune constantă cu un alt socket. 
- 
-Funcția ''​recvfrom''​ citește date similar cu funcția ''​recv'',​ dar întoarce două obiecte: mesajul și adresa sursei. Astfel, putem folosi adresa returnată pentru a trimite mesaje înapoi. Aceasta funcție este potrivită pentru transmiterea de tip UDP, unde nu avem o conexiune cu un alt socket. 
-<note info> 
-Obiectul ''​address''​ returnat este un tupul de tipul (adress, port), ex: ("​0.0.0.0",​ 8000). 
-</​note> ​ 
- 
-=====Exemple===== 
-În aceste exemple vom crea un proces care așteaptă continuu mesaje si răspunde la acestea (server) și un alt proces care trimite un mesaj și asteaptă un răspuns (client). 
-<note info> 
-Pentru a putea testa comunicarea pe rețea folosind un singur calculator, vom crea două fișiere sursă, fiecare simulând comportamentul unei stații diferite în rețea. Pentru a testa comunicarea,​ vom rula cele două programe în paralel. 
-</​note>​ 
-====Exemplu UDP==== 
-===Server=== 
-<code python> 
-import socket 
- 
-buffersize = 2048 
-# create socket 
-s = socket.socket(family=socket.AF_INET,​ type=socket.SOCK_DGRAM) 
-# bind socket to address and port 
-s.bind (("​0.0.0.0",​ 8000)) 
- 
-# listen for data forever and reply with "​Message received"​ 
-while True: 
-    data, addr = s.recvfrom(buffersize) 
-    print ("Data from {} is {}"​.format (addr, data)) 
-    msg = str.encode ("​Message received"​) 
-    s.sendto (msg, addr) 
-</​code>​ 
-===Client=== 
-<code python> 
-import socket 
-buffersize = 2048 
- 
-# create socket 
-s = socket.socket(family=socket.AF_INET,​ type=socket.SOCK_DGRAM) 
-# create bytes object 
-msg = str.encode("​Hello"​) 
-# send message 
-s.sendto (msg, ("​localhost",​ 8000)) 
-# read message 
-data, addr = s.recvfrom (buffersize) 
-print ("Data from {} is {}"​.format (addr, data)) 
-</​code>​ 
- 
-<note info> 
-Pentru a testa exemplul, rulați prima dată serverul și apoi clientul într-un alt terminal. 
-</​note>​ 
- 
-====Exemplu TCP==== 
-===Server=== 
-<code python> 
-import socket 
- 
-buffersize = 2048 
-# create socket 
-s = socket.socket (family=socket.AF_INET,​ type=socket.SOCK_STREAM) 
-# bind socket to address and port 
-s.bind (("​0.0.0.0",​ 8000)) 
-# wait for connections 
-s.listen (0) 
-# accept connections forever 
-while True: 
-    conn, addr = s.accept () 
-    print ("​Connected to {}"​.format (addr)) 
- 
-    # listen for data and reply with "​Message received"​ 
-    while True: 
-        data = conn.recv(buffersize) 
-        # client finished sending message 
-        if not data: 
-            break 
-        print ("​Received {}"​.format (data)) 
-        msg = str.encode ("​Message received"​) 
-        conn.send (msg) 
-    # close connection 
-    conn.close () 
-</​code>​ 
- 
-===Client=== 
-<code python> 
-import socket 
-buffersize = 2048 
- 
-# create socket 
-s = socket.socket(family=socket.AF_INET,​ type=socket.SOCK_STREAM) 
-# connect to server 
-s.connect (("​localhost",​ 8000)) 
-# create bytes object 
-msg = str.encode("​Hello"​) 
-# send message 
-s.send (msg) 
-# read message 
-data, addr = s.recv (buffersize) 
-# close connection 
-s.close () 
- 
-print ("Data from {} is {}"​.format (addr, data)) 
-</​code>​ 
- 
- 
-====== Exerciţii de laborator ====== 
- 
-În rezolvarea laboratorului folosiți repository-ul de github. Pentru a descărca repository-ul,​ rulati comanda git clone https://​github.com/​UPB-FILS/​sde.git in terminal. 
- 
-===== Exercițiul 1 - Informații rețea ===== 
-  - Creați un program care afișează adresa fizică, adresa IP și numele stației. 
-  - Afișați adresa IP a ''​google.com''​. 
- 
-===== Exercițiul 2 - Netcat ===== 
-Netcat este un utilitar în linie de comandă care permite efectuarea de operații pe rețea. În acest exercițiu îl vom folosi pentru a schimba mesaje cu programele python din exemplele de mai sus. 
-  - Rulați aplicația server din exemplul de transmisie TCP, după care într-un alt terminal, în paralel, rulați comanda: ''​netcat -z -v localhost 8000''​. Observați răspunsul primit. 
-  - Rulați aplicația server din exemplul de transmisie UDP, după care într-un alt terminal, în paralel, rulați comanda: ''​echo test | netcat -u localhost 8000''​. Observați comportamentul rezultat (opțiunea -u specifică modul de transmisie UDP).  
-  - Trimiteți un mesaj către programul server TCP folosind ''​netcat''​. 
-  - Rulați comanda netcat -lu -p 8080, care pornește un server UDP pe portul 8080. Modificați exemplul din laborator pentru a trimite un mesaj server-ului pornit. 
-  - Rulați comanda netcat -l -p 8080, care pornește un server TCP pe portul 8080. Modificați exemplul din laborator pentru a trimite un mesaj server-ului pornit. 
- 
-===== Exercițiul 3 - Comunicare TCP ===== 
-În comunicarea TCP, portul serverului este folosit doar pentru a accepta conexiuni. Odată ce conexiunea este stabilită, acesteia i se atribuie un alt port pe care se realizează comunicarea efectivă. Modificați exemplul de mai sus pentru a afișa portul atribuit conexiunii (variabila ''​conn''​). Hint: [[https://​docs.python.org/​3/​library/​socket.html#​socket.socket.getsockname|getsocketname]]. 
- 
-===== Exercițiul 3 - UDP ===== 
- 
-Creați două programe care comunică în mod UDP prin socket astfel încât unul din programe să primească trei numere separate prin '';''​ și să răspundă cu media aritmetică a acestora. 
- 
- 
-===== Exercițiul 4 - Server TCP ===== 
-Simulați un server TCP care primește comenzi bash și răspunde cu rezultatul acestora. Creați un client care trimite comenzi și afișează rezultatul primit de la server. 
-===== Exercițiul 5 - Server TCP multi-threaded ===== 
-Modificați serverul creat la punctul anterior pentru a suporta mai multe conexiuni simultane. Folosiți threaduri în implementare. 
-Hint: programul principal acceptă conexiunile,​ iar odată stabilită conexiunea, porniți un nou thread care primește ca parametru conexiunea. 
-<​hidden>​ 
-===== Exercițiul 6 - client Web ===== 
-- sa ia date de pe internet 
-===== Exercițiul 7 - Simple HTTP Server ===== 
-- sa faca server cu simple http server 
-</​hidden>​ 
- 
  
sde/laboratoare/10_ro_python.1587479936.txt.gz · Last modified: 2020/04/21 17:38 by ioana_maria.culic
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0