42
MREŽNO RAČUNARSTVO Soketi za klijente (iz 8. poglavlja u 4. izdanju) 1

Mrežno računarstvo - ncd.matf.bg.ac.rs

  • Upload
    others

  • View
    10

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Mrežno računarstvo - ncd.matf.bg.ac.rs

MREŽNO RAČUNARSTVO

Soketi za klijente

(iz 8. poglavlja u 4. izdanju)

1

Page 2: Mrežno računarstvo - ncd.matf.bg.ac.rs

Soketi za klijente

• podaci se šalju preko Interneta u paketima ograničene veličine, koji se nazivaju datagram-ima

• datagram ima header i payload

• header – adresa i port kuda paket ide, adresa i port odakle dolazi itd. ostali podaci neophodni za pouzdani prenos

• payload – sami podaci

2

Page 3: Mrežno računarstvo - ncd.matf.bg.ac.rs

Soketi za klijente

•podela podataka u pakete•njihovo spajanje na odredištu•izgubljeni i oštećeni paketi koje treba ponovo poslati

•paketi ne stižu dobrim redosledom, pa ih treba preurediti

•dakle, podela u paketa, generisanje zaglavlja, parsiranje zaglavlja dolazećih paketa, praćenje koji paketi jesu, a koji nisu pristigli – tu ima dosta posla

3

Page 4: Mrežno računarstvo - ncd.matf.bg.ac.rs

Soketi za klijente

• Srećom, mi o tome ne moramo da brinemo.

• Soketi omogućavaju programeru da tretira mrežnu konekciju kao još jedan stream u koji može pisati bajtove, odnosno iz kojih može čitati bajtove

• Soketi štite programera od detalja nižeg nivoa, poput otkrivanja grešaka, veličina paketa, retransmisije paketa, itd.

4

Page 5: Mrežno računarstvo - ncd.matf.bg.ac.rs

Osnove soketa

•Soket predstavlja konekciju između dva hosta•On može vršiti 7 osnovnih operacija:

• povezivanje na udaljenu mašinu (connect)• slanje podataka (send)• primanje podataka (receive)• zatvaranje konekcije (close)• povezivanje na port (bind to port)• osluškivanje dolazećih podataka (listen)• prihvatanje konekcija sa udaljenih mašina na

povezanom portu

5

Page 6: Mrežno računarstvo - ncd.matf.bg.ac.rs

Socket klasa (i ServerSocket)

• klasa Socket, koju koriste i klijenti i serveri, ima metode koji odgovaraju prvim 4 od prethodnih 7 operacija

• Poslednje 3 operacije neophodne su samo serverima, koji čekaju da ih klijenti kontaktiraju. Ove operacije implementirane su klasom ServerSocket

6

Page 7: Mrežno računarstvo - ncd.matf.bg.ac.rs

uobičajeno korišćenje soketa za klijente• Java programi obično koriste klijentske sokete na

sledeći način• program konstruktorom kreira novi soket• soket pokušava da se konektuje na udaljeni host• nakon što je konekcija uspostavljena, lokalni i udaljeni host

uzimaju input i output stream-ove od soketa i koriste te stream-ove da šalju podatke jedan drugome. Konekcija je full-duplex, što znači da oba hosta mogu da primaju i šalju podatke istovremeno. Šta su podaci, zavisi od protokola; različite komande se šalju FTP serveru nego HTTP serveru

• kada je prenos podataka završen, jedna ili obe strane zatvaraju konekciju. Neki protokoli, poput HTTP 1.0 zahtevaju da se konekcija zatvori nakon obrade svakog zahteva. Drugi, poput FTP dopuštaju obradu većeg broja zahteva jednom konekcijom

7

Page 8: Mrežno računarstvo - ncd.matf.bg.ac.rs

klasa Socket

•java.net.Socket•osnovna klasa za izvršavanje client-side TCP operacija

•ostale klijentski orijentisane klase koje prave TCP mrežne konekcije (URL, URLConnection, Applet, JEditorPane) pozivaju metode ove klase

•interfejs koji klasa obezbeđuje programeru su stream-ovi. Stvarno čitanje i pisanje podataka preko soketa vrši se poznatim stream klasama

8

Page 9: Mrežno računarstvo - ncd.matf.bg.ac.rs

konstruktori

• jednostavni• svaki dopušta da se zada host i port na koji želimo da se

konektujemo• host se može zadati kao InetAddress ili String• portovi se uvek zadaju kao int vrednosti od 0 do 65535• 2 konstruktora takođe zadaju lokalnu adresu i lokalni port sa

kojih se šalju podaci (to je možda potrebno kada se želi izabrati jedan određeni mrežni interfejs sa kog se šalju podaci, ako ih je više)

• postoje i 2 konstruktora koja kreiraju nekonektovane sokete. Oni su korisni kada se žele postaviti opcije soketa pre pravljenja prve konekcije

9

Page 10: Mrežno računarstvo - ncd.matf.bg.ac.rs

public Socket(String host, int port) throws UnknownHostException, IOException

• kreira TCP soket ka zadatom portu i zadatom hostu i pokušava da se konektuje na udaljeni hosttry{

Socket toOReilly = new Socket("www.oreilly.com", 80);// send and receive data …

}catch(UnkownHostException ex){System.err.println(ex);

}catch(IOException ex){System.err.println(ex);

}

10

Page 11: Mrežno računarstvo - ncd.matf.bg.ac.rs

• host je hostname (String). Ako domain name server ne može da razreši hostname ili ne funkcioniše, izbacuje se UnkownHostException

• ako soket ne može biti otvoren iz drugih razloga, izbacuje se IOException. Mnogi su razlozi: taj host možda ne prihvata konekcije, dialup konekcija je možda pukla, ili problemi rutiranja sprečavaju pakete da stignu do odredišta

• ovaj konstruktor ne samo da kreira soket, već takođe pokušava da konektuje soket na udaljeni host, pa se ovaj objekat može koristiti za utvrđivanje da li su dopuštene konekcije na određeni port

• primer 1 (LowPortScanner)

11

Page 12: Mrežno računarstvo - ncd.matf.bg.ac.rs

Primer - objašnjenja

• na Unix sistemima, koji servisi su na kojim portovima može se videti u fajlu /etc/services

• program na Unix sistemima treba da nađe tačno portove iz tog fajla

• ne koristite LowPortScanner da probate na mašini koju ne posedujete, jer većina sistem administratora to smatra neprijateljskim činom

12

Page 13: Mrežno računarstvo - ncd.matf.bg.ac.rs

public Socket(InetAddress host,int port) throws IOException•radi isto što i prethodni konstruktor (kreira TCP soket ka zadatom portu na zadatom hostu) i pokušava da se konektuje

•razlikuje se po tome što koristi InetAddressobjekat za zadavanje hosta (umesto hostname)

•izbacuje IOException ako ne može da se konektuje, ne i UnknownHostException: ako je host nepoznat, saznaćemo kada kreiramo InetAddress objekat

13

Page 14: Mrežno računarstvo - ncd.matf.bg.ac.rs

• primer upotrebe:try{

InetAddress oreilly = InetAddress.getByName("www.oreilly.com");Socket oreillySocket = new Socket(oreilly, 80);// send and receive data …

} catch(UnknownHostException ex){System.err.println(ex);

} catch(IOException ex){System.err.println(ex);

}• U retkim situacijama kada otvarate mnogo soketa na istom hostu,

efikasnije je konvertovati hostname u InetAddress i zatim koristiti InetAddress za kreiranje soketa.

• Primer 2 (HighPortScanner)

14

Page 15: Mrežno računarstvo - ncd.matf.bg.ac.rs

ostali konstruktori

• … page 8 of 65

• još 2 argumenta: lokalni mrežni interfejs i port

• ako se za port izabere 0, Java bira slučajan dostupan port između 1024 i 65535

• ... page 10 of 65

• konstruktori koji kreiraju sokete koji ne pokušavaju da se konektuju

15

Page 16: Mrežno računarstvo - ncd.matf.bg.ac.rs

Dobijanje informacija o soketu

• public InetAddress getInetAddress() koji je udaljeni host na koji je soket konektovan, ili, ako je konekcija zatvorena, na koji je soket bio konektovan dok je bio konektovan

• public int getPort()koji je port na udaljenom hostu na koji je soket bio, je ili će biti konektovan

• public int getLocalPort()(postoje 2 kraja konekcije: remote i local host)Za razliku od remote porta koji je (za klijenta) obično dobro poznat, local port se obično bira od strane sistema u vreme izvršavanja od dostupnih neiskorišćenih portova. Na ovaj način, mnogi različiti klijenti mogu pristupati istom servisu u isto vreme. Local port je ugrađen u IP pakete zajedno sa IP adresom local host-a, tako da server može poslati podatke nazad na pravi port klijenta.

• public InetAddress getLocalAddress()za koji mrežni interfejs je soket vezan. Ovo se obično koristi na hostu sa većim

brojem mrežnih interfejsa• primer 3, SocketInfo

16

Page 17: Mrežno računarstvo - ncd.matf.bg.ac.rs

public InputStream getInputStream()throws IOException

•vraća ulazni tok koji može čitati podatke iz soketa u program

•obično se olančava ovaj InputStream na filter tok ili čitač koji nudi veću funkcionalnost –DataInputStream ili InputStreamReader, npr. pre čitanja ulaza.

•Zbog poboljšanja performansi, jako je dobra ideja baferisati ulaz olančavanjem na BufferedInputStream i/ili BufferedReader

17

Page 18: Mrežno računarstvo - ncd.matf.bg.ac.rs

daytime protokol (RFC 867)

•Sa ulaznim tokom, možemo čitati podatke iz soketa i početi eksperimentisanje sa nekim stvarnim Internet protokolima

•jedan od najjednostavnijih je daytime•klijent otvara soket na portu 13 daytime servera•kao odgovor, server šalje vreme u čitljivom formatu

i zatvara konekciju•”Wed Nov 12 23:39:15 2003” linija koju je poslao

server•primer 4, DaytimeClient

18

Page 19: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 4, objašnjenja

• DaytimeClient čita hostname daytime servera iz komandne linije i koristi ga za konstruisanje novog Soketa koji se konektuje na port 13 servera

• ako se izostavi hostname, the National Institute of Standards and Technology server na time.nist.gov se koristi

• klijent zatim poziva theSocket.getInputStream() da dobije ulazni tok od soketa, i smešta taj tok u promenljivu timeStream

• pošto daytime protokol specifikuje ASCII, DaytimeClient ne olančava čitač na tok. On samo čita bajtove u StringBuffer, jedan po jedan, prekidajući kada server zatvori konekciju pošto protokol to od njega zahteva.

19

Page 20: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 4, objašnjenja

•vremenski serveri na različitim host-ovima koriste različite formate.

•daytime protokol ne određuje format u kome se vraća vreme, osim da bude čitljiv

•zato, teško je konvertovati karaktere koje vrati server u Java Date na pouzdan način.

•Ako želimo da kreiramo Date objekat na osnovu vremena na serveru, lakše je koristiti time protokol iz RFC 868, jer on određuje format vremena

20

Page 21: Mrežno računarstvo - ncd.matf.bg.ac.rs

Time protocol (RFC 868)

•Kada se čitaju podaci sa mreže, bitno je imati na umu da ne koriste svi protokoli ASCII, čak ni tekst

•npr, time protokol zadat u RFC 868 zadaje da se vreme šalje kao broj sekundi od ponoći 1. januara 1900 po Griniču (GMT)

•Međutim, to se ne šalje kao ASCII string ”2,524,521,600” ili ”-1297728000”, već kao 32-bitni, neoznačeni, big-endian binarni broj

21

Page 22: Mrežno računarstvo - ncd.matf.bg.ac.rs

• RFC podrazumeva da znamo da svi mrežni protokoli koriste big endian brojeve• primer 5 (TimeClient)• Pošto ovo nije tekst, naš program ne može čitati odgovor servera pomoću

Reader-a niti bilo koje vrste readLine() metoda.• Java program koji se konektuje na time servere mora čitati neobrađene bajtove

i interpretirati ih na odgovarajući način• U ovom primeru, taj posao komplikuje nedostatak 32-bitnog neoznačenog

celobrojnog tipa u Javi.• Zato, bajtovi se moraju čitati jedan po jedan i ručno konvertovati u long

korišćenjem bitskih operatora << i |.• Kada se radi o drugim protokolima, oni mogu baratati formatima podataka koji

su još čudniji za Javu, npr. nekoliko mrežnih protokola koristi 64-bitne brojeve u fiksnom zarezu. Tu nema prečice koja će rukovati svim mogućim slučajevima. Prosto, mora se iskodirati sva matematika neophodna za rukovanje podacima u onom formatu koji server pošalje.

22

Page 23: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 5 objašnjenja

•program čita hostname servera i opcioni port iz komandne linije i koristi ih za konstruisanje novog Socket objekta koji se konektuje na taj server

•Ako korisnik izostavi hostname, koristi se time.nist.gov

•podrazumevani port je 37•klijent zatim poziva theSocket.getInputStream() da dobije ulazni tok, koji smešta u prom. raw

23

Page 24: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 5 objašnjenja

• 4 bajta se čitaju iz ovog toka i koriste za konstruisanje long-a koji predstavlja vrednost ta 4 bajta interpretiranu kao 32-bitni neoznačeni ceo broj

• ovo daje broj sekundi proteklih od 12:00 A.M. January 1, 1900 GMT (time protocol epoch)

• 2,208,988,800 sekundi se oduzima od tog broja da bi se dobio broj sekundi proteklih od 12:00 A.M. January 1, 1970 GMT (Java Date class epoch)

• ovaj broj se množi sa 1000 da bi se konvertovao u milisekunde

• konačno, taj broj milisekundi konvertuje se u Date objekat koji se štampa kako bi prikazao tekuće vreme i datum

24

Page 25: Mrežno računarstvo - ncd.matf.bg.ac.rs

public OutputStream getOutputStream()throws IOException

• vraća neobrađeni OutputStream za pisanje podataka iz naše aplikacije drugom kraju soketa

• obično olančavamo ovaj tok klasama DataOutputStream ili OutputStreamWriter pre njegovog korišćenja

• Za poboljšanje performansi, dobra ideja je baferisati ga, takođe.

25

Page 26: Mrežno računarstvo - ncd.matf.bg.ac.rs

Writer out;

try{

Socket http = new Socket(”www.oreilly.com”,80);

OutputStream raw = http.getOutputStream();

OutputStream buffered = new BufferedOutputStream(raw);

out = new OutputStreamWriter(buffered, ”ASCII”);

out.write(”GET / HTTP 1.0\r\n\r\n”);

// read the server response …

}

catch(Exception ex){

System.err.println(ex);

}

finally{

try{

out.close();

}

catch(Exception ex){}

}

26

Page 27: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 6, echo protocol

•echo protokol, definisan u RFC 862, jedan je od najjednostavnijih interaktivnih TCP servisa

•klijent otvara soket na portu 7 echo servera i šalje podatke

•server šalje podatke nazad•ovo se nastavlja dok klijent ne zatvori konekciju•echo protokol je koristan za testiranje mreže, kako bismo bili sigurni da podaci nisu izopačeni pogrešnim ponašanjem rutera ili firewall-a.

27

Page 28: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 6, objašnjenja

• primer koristi getOutputStream() i getInputStream() da implementira jednostavni echo klijent.

• korisnik kuca ulaz u komandnoj liniji, koji se zatim šalje serveru• server ga vraća nazad• program se završava kada korisnik ukuca tačku u posebnoj liniji• echo protokol ne određuje kodiranje karaktera. Zapravo, on zadaje da

su podaci poslati serveru tačno oni koje server vraća. Server vraća neobrađene bajtove, ne karaktere koje oni predstavljaju. Tako, ovaj program koristi podrazumevano karaktersko kodiranje i line separator klijentskog sistema za čitanje iz System.in, slanje podataka udaljenom sistemu i ispis izlaza na System.out.

• Kako echo server vraća upravo ono što je poslato, to je kao da se server dinamički podešava prema klijentskim konvencijama za karaktersko kodiranje i prelom linija.

• Zato, koriste se uobičajene klase i metodi poput PrintWriter i readLine() koje bi u opštem slučaju bile previše nepouzdane

28

Page 29: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 6, objašnjenja

• novi Socket objekat, theSocket, kreira se na portu 7• InputStream soketa vraća se metodom getInputStream() i olančava na

InputStreamReader, a ovaj na BufferedReader nazvan networkIn koji čita odgovore servera

• Pošto ovaj klijent takođe treba da čita ulaz korisnika, on kreira drugi BufferedReader, koji se zove userIn i čita iz System.in

• Dalje, EchoClient poziva theSocket.getOutputStream() da dobije izlazni tok soketa theSocket, koji se koristi za konstruisanje novog PrintWriter objekta out.

• Podaci se čitaju iz userIn i pišu na out.• Nakon što se podaci pošalju echo serveru, networkIn čeka odgovor.• Kada odgovor stigne, on se štampa na System.out.• Teoretski, klijent bi mogao da čeka na odovor koji nikada ne stiže. Međutim, to

nije verovatno ako se može napraviti konekcija, pošto TCP protokol proverava loše pakete i automatski traži od servera zamene. Za implementiranje UDP echo klijenta (glava 13) potreban je drugačiji pristup jer UDP ne vrši kontrolu grešaka.

29

Page 30: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer 6, objašnjenja• primer je linijski-orijentisan• on čita liniju iz konzole, šalje je serveru, i čeka da pročita liniju

koju mu ovaj vrati• međutim, echo protokol to ne zahteva• on vraća svaki bajt pošto ga primi• nije mu stalo da ti bajtovi predstavljaju karaktere u istom

kodiranju ili da budu podeljeni u linije• Java ne dopušta da se konzola prebaci u ”neobrađeni” mod,

gde se svaki karakter čita čim se ukuca umesto čekanja da korisnik pritisne Enter.

• Za razliku od mnogih protokola, echo ne zahteva da klijent pošalje zahtev, a onda čeka na pun odgovor servera pre nego što pošalje još podataka. Najjednostavniji način za rukovanje takvim protokolom u Javi je smestiti mrežni ulaz i izlaz u odvojene niti.

30

Page 31: Mrežno računarstvo - ncd.matf.bg.ac.rs

Zatvaranje soketa

• ovo je skoro sve što je potrebno znati o soketima

• kada se piše klijentska aplikacija, skoro sav posao je rukovanje tokovima i interpretiranje podataka

• sa samim soketima se radi jednostavno (svi teški delovi skriveni su od programera)

31

Page 32: Mrežno računarstvo - ncd.matf.bg.ac.rs

public void close() throws IOException• primeri do sada podrazumevali su da se soketi sami

zatvaraju i nisu radili ništa da počiste za sobom• tačno je da se soket automatski zatvara kada se zatvori

jedan od njegova dva stream-a, kada se završi program, ili kada ga počisti garbage collector.

• Međutim, loša je praksa pretpostavljati da će sistem zatvarati naše sokete, posebno za programe koji se mogu izvršavati neograničeno dugo

• u programima koji intenzivno koriste sokete, poput web browser-a, sistem može dostići max broj otvorenih soketa pre nego što ih pokupi garbage collector.

• primeri 1 i 2 su naročito loši u tom pogledu, pošto može proteći puno vremena dok program prođe sve portove

32

Page 33: Mrežno računarstvo - ncd.matf.bg.ac.rs

• kada završite sa soketom, treba pozvati njigov close() metod za diskonektovanje

• idealno, on se stavlja u finally blok tako da se soket zatvara bez obzira da li je izbačen izuzetak ili ne

• sintaksa je pravolinijska

33

Page 34: Mrežno računarstvo - ncd.matf.bg.ac.rs

Socket connection = null;try{connection = new Socket(”www.oreilly.com” , 13);// interact with the socket…

} // end trycatch(UnknownHostException ex){System.err.println(ex);

} catch(IOException ex){System.err.println(ex);

}finally{if(connection != null) connection.close();

}

34

Page 35: Mrežno računarstvo - ncd.matf.bg.ac.rs

•nakon što je soket zatvoren, njegov InetAddress, broj porta, lokalna adresa i lokalni broj porta su još uvek dostupni preko odgovarajućih get*() metoda

•međutim, iako je moguće zvati getInputStream() ili getOutputStream(), pokušaj čitanja ili pisanja podataka dovodi do izbacivanja IOException

•primer 7, revizija PortScanner programa koja zatvara svaki soket kada završi sa njim. Ne zatvara sokete koji nisu uspeli da se konektuju. Pošto oni nisu nikada otvoreni, ne moraju se zatvoriti. Zapravo, kada konstruktor ne uspe, connection ima vrednost null.

35

Page 36: Mrežno računarstvo - ncd.matf.bg.ac.rs

public boolean isClosed()

•vraća true ako je soket zatvoren, false inače•ako niste sigurni kakvo je stanje soketa, možete

proveriti ovim metodom, radije nego da reskirate IOException

•if(socket.isClosed())// do something ...

else// do something else

•međutim, ovo nije savršen test. ako soket nikada nije bio konektovan, isClosed() vraća false, čak i kada soket nije otvoren

36

Page 37: Mrežno računarstvo - ncd.matf.bg.ac.rs

public boolean isConnected()•ime može da zavara•ovaj metod ne kaže da li je soket trenutno konektovan na udaljeni host, već da li je soket ikada bio konektovan na udaljeni host.

•ako je soket bio u mogućnosti da se konektuje na udaljeni host ikada, metod vraća true, čak i ako je soket zatvoren

•za proveru da li je soket trenutno otvoren, mora se proveriti da isConnected() vraća true i isClosed() vraća false.

•boolean connected = socket.isConnected() && !socket.isClosed();

37

Page 38: Mrežno računarstvo - ncd.matf.bg.ac.rs

public boolean isBound()

• odnosi se na lokalni kraj soketa

• metod kaže da li je soket uspešno povezan na izlazni port lokalnog sistema. To u praksi nije vrlo važno. Postaće važnije kod serverskih soketa

38

Page 39: Mrežno računarstvo - ncd.matf.bg.ac.rs

poluzatvoreni soketi

• close() metod zatvara oba input i output soketa• povremeno, želimo da zatvorimo samo pola konekcije, bilo

izlaz bilo ulaz• public void shutdownInput() throws IOException• public void shutdownOutput() throws IOException• Ovo ne zatvara soket. Ali podešava tok povezan na njega da

misli da je kraj toka. Dalje čitanje iz ulaznog toka vraća -1. Dalje pisanje u izlazni tok izbacuje IOException.

• Mnogi protokoli, poput finger, whois, HTTP počinju tako što klijent šalje zahtev serveru, a zatim čita odgovor. Moguće je zatvoriti izlaz nakon što klijent pošalje zahtev.

39

Page 40: Mrežno računarstvo - ncd.matf.bg.ac.rs

primer• Sledeći fragment koda šalje zahtev HTTP serveru i onda zatvara izlaz, pošto neće više ništa pisati serveru preko tog soketa

Socket connection = null;try{connection = new Socket(”www.oreilly.com”, 80);Writer out = new OutputStreamWriter(connection.getOutputStream, ”8859_1”);out.write(”GET / HTTP 1.0\r\n\r\n”);out.flush();connection.shutdownOutput();// read the response …

}catch(IOException ex){}finally{try{

if(connection!=null) connection.close();}catch(IOException ex){}

}40

Page 41: Mrežno računarstvo - ncd.matf.bg.ac.rs

•primetite da iako zatvorite pola, ili obe polovine konekcije, još uvek treba da zatvorite soket kada završite sa njim.

•shutdown metodi prosto utiču na tokove soketa. Oni ne oslobađaju resurse pridružene soketu poput porta koji on zauzima

•public boolean isInputShutdown()•public boolean isOutputShutdown()•ovi metodi se mogu koristiti (radije nego isConnected() i isClosed()) za određeniju proveru da li se može pisati ili čitati iz soketa

41

Page 42: Mrežno računarstvo - ncd.matf.bg.ac.rs

page 30 of 65 (3. izdanje)

• 9.3.4 Setting Socket Options (3.izdanje)

page 39 of 65• 9.6 Examples

42