Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Informatika-Osnove mrežnog programiranja-
Izv. prof. dr. sc. Marija Seder
Sadržaj IP adrese, portovi i socket-i za stvaranje
jednostavnih klijent-poslužitelj aplikacija na mreži
Aplikacija klijent-poslužitelj koja javlja vrijeme spajanja na poslužitelj● izvedba s TCP protokolom● izvedba s UDP protokolom
Aplikacija za chat između klijenta i poslužitelja● izvedba s UDP protokolom
2
Mreže, klijenti i poslužitelji Klijenti i poslužitelji su aplikacije ili procesi koji
se izvode lokalno na jednom računalu ili udaljeno kroz mrežu računala
Resursi zahtjevani za ovakav tip aplikacije su: IP adrese Socket-i
3
Mreže, klijenti i poslužitelji Svako računalo na mreži ima jedinstvenu IP
adresu koja omogućava drugim računalima da ga pronađu
Poslužitelji i klijenti komuniciraju na mreži putem socket-a
Klijenti i poslužitelji komuniciraju slanjem i primanjem stringova kroz svoje socket veze
Poslužitelj može prihvaćati i obrađivati nekoliko klijenata istovremeno tako što svakome klijentu pridružuje posebnu dretvu
4
IP adrese Računalo na mreži ima jedinstveni identifikator
koji se zove IP adresa (IP: Internet Protocol) Može se specificirati kao IP broj
Format: a.b.c.d (a,b,c,d su brojevi od 0 do 255) Primjer: 137.112.194.77
Može se specificirati kao IP ime Primjer: ivan-laptop
Pythonov modul socket sadrži dvije funkcije koje mogu doći do informacije o IP adresi
gethostname() gethostbyname(imeIP)gethostbyname(gethostname()) - skraćeno
5
IP adrese – naredbe iz modula socket gethostname() – vraća IP ime host računala na kojem
se vrti Python (naše računalo, računalo domaćin), a javlja grešku (exception) ako IP adresa nije konfigurirana
gethostbyname(imeIP) – vraća IP broj računala koje ima IP ime imeIP, a javlja grešku (exception) ako IP ime nije prepoznato ili pronađeno
u slučaju greške nekad ne želimo prekinuti izvođenje programa – tada koristimo naredbe try i except:
try:naredba
except ImeGreske:naredba, npr ispis u slučaju greške
6
IP adrese – primjeri >>> from socket import *>>> gethostname()'marija-Latitude-7490'>>> gethostbyname('marija-Latitude-7490')'192.168.1.4'>>> gethostbyname(gethostname())'192.168.1.4'>>> gethostbyname('www.google.com')'172.217.18.4'
7
IP adrese – primjeri (nastavak) >>> gethostbyname('marija')
Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> gethostbyname('marija')gaierror: [Errno -5] No address associated with hostnametry:
gethostbyname('marija')except gaierror:
print 'ne postoji racunalo'
ne postoji racunalo
8
Portovi, poslužitelji i klijenti Klijenti se povezuju na poslužitelje preko portova Portovi služe kao kanali kroz koji nekoliko klijenata
mogu razmijeniti podatke s istim poslužiteljem ili s više poslužitelja
Uobičajeno je označen brojevima Neki portovi su posvećeni posebnim serverima ili
zadacima Primjer: 13 za server za dan/vrijeme ili 80 za Web server
Većina računala ima stotine ili čak tisuću slobodnih portova za korištenje bilo koje mrežne aplikacije - brojevi su od 0 do 65535
9
Socket-i Socket: objekt koji služi kao komunikacijska
veza između poslužiteljskog procesa i klijentskog procesa Može stvoriti/otvoriti nekoliko socket-a na istom
portu
10
Socket-i: primjer klijentTCPweb.py
11
Ovaj primjer stvara socket sa sljedećim svojstvima: Familija adresa: AF_INET znači IP verzija 4 ili IPv4 Tip veze SOCK_STREAM znači TCP protokol Tip veze SOCK_DGRAM znači UDP protokol defaultni je TCP - može se pisati bez argumenata
#Primjer socket klijenta u pythonufrom socket import * #za socketeimport sys #za exit#stvori AF_INET, STREAM socket (TCP) – to je default!#s = socket(AF_INET, SOCK_STREAM)s = socket()print 'Socket je stvoren'
Socket-i: primjer klijentTCPweb.py
12
Sljedeći korak je spojiti se na neki poslužitelj koristeći ovaj socket – pokušajmo na google! trebamo IP ime ili adresu i broj porta – u pythonu
je to jednostavno broj porta za google je 80 (i većinu web
poslužitelja)from socket import * #za socketeimport sys #za exit#stvori AF_INET, STREAM socket (TCP)s = socket()print 'Socket je stvoren' host = 'www.google.com'port = 80
Socket-i: primjer klijentTCPweb.py
13
ako nema konekcije želimo ispisati grešku i prekinuti klijentsku aplikaciju
...try:#Spajamo se na udaljeni server
s.connect((host , port))except error, msg: print 'Vezanje nije uspjelo. Kod greske: ',msg sys.exit()print 'Socket connect uspio'
Socket-i: primjer klijentTCPweb.py
14
Objašnjenje connect-a: Tip veze: SOCK_STREAM ili TCP stvara socket kao
cijev kroz koju teku podaci određenim redoslijedom. Moguće je stvoriti više takvih konekcija koje su samostalne, odnosno svaka ima svoju komunikaciju neovisnu o drugima.
Postoje drugi tipovi veze: SOCK_DGRAM ili UDP, koji nema koncept konekcije, odnosno podaci se šalju prema svima i primaju od svih bez provjera od koga je podatak došao.
Socket-i: primjer klijentTCPweb.py
15
Slanje i primanje podataka: funkcija send šalje podatak na poslužitelj kao string funkcija recv prima podatak s poslužitelja
Slanje podatka – u primjeru se šalje poruka koja je http naredba za dohvat stranice - GET
Primanje odgovora sa poslužitelja na naredbu GET
Socket-i: primjer klijentTCPweb.py
16
Slanje i primanje podataka (nastavak)...#Posaljimo podatke na udaljeni serverporuka = "GET / HTTP/1.0\r\n\r\n" s.send(poruka)
#primanje podatka u while petlji da dohvatimo svewhile 1:
odgovor = s.recv(1000) print odgovor
if not odgovor:break;
s.close()
Socket-i: primjer klijentTCPweb.py
17
Primjer ispisa za host webcode.me:HTTP/1.1 200 OKServer: nginx/1.6.2Date: Sun, 15 Dec 2019 20:37:43 GMTContent-Type: text/htmlContent-Length: 348Last-Modified: Sat, 20 Jul 2019 11:49:25 GMTConnection: closeETag: "5d32ffc5-15c"Access-Control-Allow-Origin: *Accept-Ranges: bytes
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My html page</title></head><body>
<p> Today is a beautiful day. We go swimming and fishing. </p> <p> Hello there. How are you? </p> </body></html>
Socket-i: primjer klijentTCPweb.py
18
Zaključak: naučili smo stvoriti socket s TCP protokolom spojiti se na udaljeni poslužitelj poslati neki podatak primiti odgovor
Korisno je znati da web preglednik također radi istu stvar kada otvorimo www.google.com – ovu stranu socket aktivnosti predstavlja KLIJENT Klijent je sustav koji se spaja na udaljeni sustav i
dohvaća podatke s njega POSLUŽITELJ predstavlja socket aktivnost na suprotnoj
strani – u ovom slučaju udaljeno računalo www.google.com Poslužitelj je sustav koji pomoću socketa prihvaća
dolazeće konekcije i omogućava im pristup podacima
Socket-i: primjer klijentUDPweb.py
19
Sljedeći primjer je spojiti se na neki poslužitelj koji podržava UDP protokol – pokušajmo na QOTD poslužitelj (Quote of the Day)
Slanje i primanje podataka UDP-om: funkcija sendto šalje podatak na poslužitelj kao
string funkcija recvfrom prima podatak s poslužitelja kao
string Slanje podatka – u primjeru se šalje prazna
poruka (string) koja je naredba za dohvat citata
Primanje odgovora sa poslužitelja
Socket-i: primjer klijentUDPweb.py
20
trebamo IP ime ili adresu i broj porta – djxmmx.net, port 17 QOTD poslužitelj odgovara na praznu poruku od klijenta
from socket import * #za sockete#stvori AF_INET, DGRAM socket (UDP)s = socket(AF_INET, SOCK_DGRAM)print 'Socket je stvoren' host = 'djxmmx.net'port = 17poruka = '' #prazna porukas.sendto(poruka,(host,port))povrat, adresa=s.recvfrom(1000)print povratprint adresas.close()
Socket-i: primjer klijentUDPweb.py
21
Objašnjenje UDP-a: Za razliku od TCP-a ne treba connect Zahtjev za porukom od poslužitelja se radi funkcijom
sendto u kojoj se navodi adresa i port poslužitelja Poslužitelj vraća odgovor klijentu koji je poslao zahtjev
(poruku). Klijent prima odgovor funkcijom recvfrom koja vraća i adresu poslužitelja koji je poslao podatak
============ RESTART:klijentUDPweb.py ==============Socket je stvoren"My spelling is Wobbly. It's good spelling but it Wobbles, and the letters get in the wrong places." A. A. Milne (1882-1958)('23.28.179.206', 17)
Programiranje poslužitelja
22
Poslužitelj na TCP protokolu radi sljedeće: otvara socket veže se na adresu i port (bind) osluškuje nadolazeće konekcije (listen) prihvaća konekcije (accept) čita/šalje podatke
Poslužitelj na UDP protokolu radi sljedeće: otvara socket veže se na adresu i port (bind) čita/šalje podatke
Programiranje TCP poslužitelja
23
Vezanje na adresu i port – funkcija bind Osluškivanje konekcija – funkcija listen: broj u zagradi
označuje koliko konekcija će čekati ako je poslužitelj zauzet: npr ako 10 konekcija čeka, 11-ta će biti odbačena
Prihvaćanje konekcija – funkcija accept... host = '' # simbolicko ime koje znaci sva moguca sucelja - prihvaćanje svih adresaport = 8888 # proizvoljni neprivilegirani ports = socket()print 'TCP Socket stvoren's.bind((host, port))s.listen(10)#cekanje konekcije – blokiranje narednih naredbiklijent, adresa = s.accept()#ispisi informacije o klijentuprint 'Spojen s', adresa
Poslužiteljska TCP skripta dan/vrijeme Možemo napisati poslužiteljsku skriptu
dan/vrijeme u Pythonu koji će obrađivati zahtjeve od više klijenata
Osnovni niz operacija poslužiteljske skripte dan/vrijeme je:
Stvoriti socket i otvoriti ga na portu 12345While True:
Čekati da se klijent spojiKad se uspostavi veza:1. poslati vrijeme klijentu2. primiti poruku od klijenta3. zatvoriti konekciju s klijentom
24
Poslužiteljska TCP skripta dan/vrijeme#servervrijeme.pyfrom socket import *from time import ctime
host = ''port = 12345 # rezerviramo ports = socket() # stvorimo socket objekts.bind((host, port))s.listen(10)
while True: print 'Cekam spajanje klijenta ...' klijent, adresa = s.accept() print '... spojen klijent s adrese', adresa klijent.send(ctime() + '\nUgodan dan!') poruka=klijent.recv(1000) print adresa,poruka klijent.close()
25
Poslužiteljska TCP skripta dan/vrijeme
26
Pokrenemo skriptu iz idle-a: u idle-u pritiskom na run module (F5)
dobit ćemo ispis:
>>> =======================RESTART========================>>> Cekam spajanje klijenta ...
Klijentska TCP skripta dan/vrijeme
27
Klijentsku skriptu moramo pokrenuti u novom idle prozoru: desni klik miša na datoteku klijentvrijeme.py i open with idle run (F5) Bitno je saznati adresu poslužitelja - na strani poslužitelja upišite
gethostbyname(gethostname())#klijentvrijeme.pyfrom socket import *import syss = socket() # stvorimo socket objekthost = '192.168.1.4' # ovdje stavimo adresu poslužiteljaport = 12345 # port poslužiteljatry: s.connect((host,port))except error, msg: print 'Vezanje nije uspjelo. Kod greske: ',msg sys.exit()print s.recv(1024) # dohvatimo poruku s poslužiteljaporuka=raw_input('unesi poruku: ')s.send(poruka) # pošaljimo poruku poslužiteljus.close() # zatvorimo socket kada smo gotovi
Klijentska TCP skripta – pokretanje
28
Klijentsku skriptu moramo pokrenuti bez prekidanja poslužiteljske skripte: u novom idle-u F5 nakon toga pogledati idle-ov prozor gdje smo pozvali
servervrijeme.py
Mon Dec 16 11:25:31 2019Ugodan dan!unesi poruku: bok!
Cekam spajanje klijenta ...... spojen klijent adrese ('192.168.1.4', 45276)('192.168.1.4', 45276) bok!Cekam spajanje klijenta ...
klijentvrijeme.py
servervrijeme.py
Primjer TCP skripti dan/vrijeme Zaključak: Mora se uspostaviti konekcija (connect)
između klijenta i poslužitelja Možemo napraviti test istovremenog spajanja
više klijenata (otvorimo još jedan idle prozor s klijentskom skriptom): poslužiteljska skripta dan/vrijeme obrađuje redom zahtjeve od više klijenata međutim ne istovremeno
Napomena: za naprednije korištenje istovremenog spajanja više klijenata u TCP protokolu koriste se dretve (thread)
29
Programiranje UDP poslužitelja
30
UDP poslužitelj prihvaća poruke od bilo kojeg klijenta i stoga ne koristi funkcije listen i accept već samo vezanje na adresu i port – funkcija bind te funkciju recvfrom koja osluškuje sve poruke na stvorenom socketu
... host = '' # simbolicko ime koje znaci sva moguca sucelja - prihvaćanje svih adresaport = 8888 # proizvoljni neprivilegirani ports = socket(AF_INET, SOCK_DGRAM)print 'UDP Socket stvoren's.bind((host, port))#cekanje podataka na stvorenom socketu – blokiranje narednih naredbipodaci, adresa = s.recvfrom(1024)#ispis informacije o klijentu koji je poslao podatakprint 'klijent s adrese',adresa,'poslao poruku: ', podaci
Poslužiteljska UDP skripta dan/vrijeme Modificirajmo poslužiteljsku skriptu
dan/vrijeme na UDP protokol Kad klijent pošalje poruku poslužitelju,
poslužitelj ju treba vratiti s porukom o vremenu
Stvoriti socket i otvoriti ga na portu 8885While True:
Čekati da klijent pošalje porukuVratiti tu poruku plus vrijeme klijentu
31
Poslužiteljska UDP skripta dan/vrijeme#servervrijemeUDP.pyfrom socket import *from time import ctime
host = ''port = 8885 # rezerviramo port
s = socket(AF_INET, SOCK_DGRAM) # UDP socket objekts.bind((host, port))
while True: print 'Cekam poruku od klijenta ...' data, adresa = s.recvfrom(1024) print 'klijent s adrese',adresa,'poslao poruku: ',data s.sendto(ctime() + ': ' + data, adresa)
32
Poslužiteljska UDP skripta dan/vrijeme
33
Pokrenemo skriptu iz idle-a: u idle-u pritiskom na run module (F5)
dobit ćemo ispis:
>>> =======================RESTART========================>>> Cekam poruku od klijenta ...
Klijentska UDP skripta dan/vrijeme
34
Klijentsku skriptu za UDP protokol moramo pripremiti u novom idle prozoru: desni klik miša na datoteku klijentvrijeme.py i open with idle run (F5) Bitno je saznati adresu poslužitelja - na strani poslužitelja upišite
gethostbyname(gethostname())
#klijentvrijemeUDP.pyfrom socket import *s = socket(AF_INET, SOCK_DGRAM) # UDP socket objekthost = '192.168.1.4' # ovdje stavimo adresu poslužiteljaport = 8885 # port poslužiteljaporuka = raw_input('unesi poruku: ')s.sendto(poruka,(host, port))odgovor,adresa=s.recvfrom(1024) # dohvatimo porukuprint odgovorprint adresa # i adresu poslužiteljas.close() # zatvorimo socket kada smo gotovi
Klijentska UDP skripta – pokretanje
35
Klijentsku skriptu moramo pokrenuti bez prekidanja poslužiteljske skripte: u novom idle-u F5 nakon toga pogledati idle-ov prozor gdje smo pozvali
servervrijeme.py
unesi poruku: bokMon Dec 16 12:19:15 2019: bok('192.168.1.4', 8885)
Cekam poruku od klijenta ...klijent s adrese ('192.168.1.4', 36563) poslao poruku: bokCekam poruku od klijenta ...
klijentvrijemeUDP.py
servervrijemeUDP.py
Primjer UDP skripti dan/vrijeme Zaključak: Ne mora se uspostaviti konekcija između klijenta i
poslužitelja već poslužitelj osluškuje poruke na zadanom portu
Svaka primljena poruka ima i informaciju o adresi klijenta
Možemo napraviti test chat aplikacije - slanje poruka s klijenta u beskonačnoj petlji i spajanje više klijenata istovremeno na jedan poslužitelj!
36
Chat aplikacija klijent - poslužiteljZadatak: Napraviti aplikaciju klijent - poslužitelj koja će
omogućiti razgovor između klijenta i poslužitelja koristeći UDP protokol
Naputak: postojeću skriptu poslužitelja proširite s upisom poruke, a skriptu klijenta proširite s beskonačnom petljom unosa poruka sve dok se ne upiše prazna poruka (pritiskom na enter)
37
Poslužiteljska UDP skripta za chat#serverchatUDP.pyfrom socket import *from time import ctime
host = ''port = 8885 # rezerviramo port
s = socket(AF_INET, SOCK_DGRAM) # UDP socket objekts.bind((host, port))
while True: print 'Cekam poruku od klijenta ...' data, adresa = s.recvfrom(1024) print 'klijent s adrese',adresa,'poslao poruku: ',data poruka=raw_input('upisi poruku: ') s.sendto(ctime() + ': ' + data + ', '+poruka, adresa)
38
Klijentska UDP skripta za chat#klijentchatUDP.pyfrom socket import *
host='192.168.1.4' # ovdje stavimo adresu poslužiteljaport=8885 # port poslužitelja
s=socket(AF_INET, SOCK_DGRAM) # UDP socket objekt
while 1: # beskonačna petlja slanja i primanja poruka poruka = raw_input('unesi poruku: ') s.sendto(poruka,(host,port)) odgovor,adresa=s.recvfrom(1024) print odgovor print adresa if not odgovor or not poruka:# ako je upisan enter print 'prazna poruka, odspajam se' breaks.close()
39
Chat aplikacija klijent - poslužiteljZaključak: Poslužitelj prima poruke od klijenta i šalje poruku
klijentu koji mu je poslao poruku Moguće je pokrenuti više klijenata istovremeno
(otvorite dodatni idle prozor i pokrenite još jednog klijenta) koji će naizmjence razmjenjivati poruke s poslužiteljem
40