Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME
u
pripremi
Portovi – protokoli – internet adrese – kreiranje
InetAddress objekata – parsiranje InetAddress objekata – URL -
U pravilu (koje ima mnogo iznimaka) svako računalo ima samo jednu Internet adresu. Međutim, svako računalo često treba komunicirati s više od jednog računala istodobno. Na primjer, u isto vrijeme može se odvijati nekoliko ftp sesija, nekoliko web konekcija, chat i tako dalje.
Da bi se to omogućilo, mrežno sučelje računala podijeljeno je na 65536 ulaza, takozvanih portova. Port je apstrakcija. To nije nikakvi fizički ulaz kao što su serijski ili paralelni portovi na osobnim računalima. No podaci putuju Internetom u paketima, pri čemu svaki paket nosi ne samo adresu hosta nego i broj porta na koji treba stići. Host će na osnovi specificiranog porta odrediti kojem programu je namijenjen dotični paket podataka.
Ako želite, IP adresu možete zamišljati kao uličnu adresu, a portove kao brojeve stanova u kućama. Routeri koji transportiraju pakete brinu se samo o “uličnoj adresi”, dakle ne čitaju broj porta. To je prepušteno lokalnom računalu.
Na Unixu potrebne su vam root privilegije za osluškivanje konekcija na portovima od 0 do 1023. Konekcije na portovima od 1024 do 65535 može osluškivati svatko, dok god određeni port nije zauzet (na istom portu ne može više od jednog programa istodobno osluškivati konekcije). Na operacijskim sustavima Windows NT, Windows 95 i Mac bilo koji korisnik može bez posebnih privilegija osluškivati bilo koji port.
Bilo koji udaljeni host može ostvariti konekciju na poslužitelj koji osluškuje neki port ispod 1024. Nadalje, višestruke simultane konekcije mogu se ostvariti na udaljeni host i udaljeni port. Na primjer, web poslužitelj koji osluškuje (u pravilu) na portu 80 može istovremeno obrađivati desetke konekcija istodobno, sve usmjerene na port 80.
Ukratko, samo jedan process na lokalnom hostu može koristiti neki port. Naprotiv, mnogo udaljenih hostova može ostvarivati konekcije na jedan te isti (udaljeni) port.
Mnogi servisi rade na tzv. općepoznatim (well-known), portovima. To znači da protokoli specificiraju da neki servis može ili mora koristiti određeni port. Na primjer, http poslužitelji obično osluškuju na portu 80, SMTP poslužitelji na portu 25, Echo poslužitelji na portu 7, a Discard poslužitelji na portu 9. Nemaju svi servisi općepoznate portove. Na primjer NFS dozvoljava da se portovi otkrivaju u vrijeme izvršavanja.
Neformalno govoreći, protocol definira kakodva hosta međusobno komuniciraju. U radio komunikaciji, na primjer, protokoli specificiraju da po završetku poruke treba reći “over” ili “kraj”. Kod računalnih mreža protokol definira što jest, a što nije prihvatljivo za jednog ili drugog sudionika komunikacije u određenom vremenskom trenutku.
Na primjer, daytime protokol, specificiran u RFC 867, kaže da se klijent povezuje s poslužiteljem na portu 13. Poslužitelj tada kaže klijentu točno vrijeme u formatu koji je za čovjeka čitljiv, a nakon toga prekida konekciju.
S druge strane, time protokol, specificiran u RFC 868, propisuje binarnu reprezentaciju vremena koja je čitljiva za računala.
Daytime i time šalju istu informaciju. Međutim, oni koriste različite formate i različite protokole da bi je poslali.
Postoji onoliko različitih vrsta protokola koliko ima servisa koji se njima koriste. Lockstep protokoli traže jedan odgovor za svaki upit. Neki protokoli kao što je FTP koriste višestruke konekcija. Većina koristi samo jednu. Neki protokoli, kao HTTP dozvoljavaju samo jedan upit i jedan odgovor po konekciji. Drugi, kao FTP, dozvoljavaju višestruke konekcije i više odgovora unutar svake konekcije.
Svako računalo na Internetu identificira se pomoću jedinstvene, četverobajtne IP adrese. Ona se obično zapisuje u tzv. dotted quad formatu kao npr. 161.53.8.14 gdje je svaki byte neoznačena vrijednost između 0 i 255.
Budući da je ovakve brojeve teško zapamtiti, adrese se mapiraju u imena kao “student.math.hr”, “jagor.srce.hr” i tako dalje. Međutim, bitna je numerička adresa, ne ime.
Klasa java.net.InetAddress
predstavlja takve adrese. Između ostalog, ona sadrži i metode za konvertiranje
numeričkih adresa u imena hostova i obrunuto.
public static InetAddress getByName(String host) throws UnknownHostExceptionpublic static InetAddress[] getAllByName(String host) throws UnknownHostExceptionpublic static InetAddress getLocalHost() throws UnknownHostExceptionpublic boolean isMulticastAddress()public String getHostName()public byte[] getAddress()public String getHostAddress()public int hashCode()public boolean equals(Object obj)public String toString()
Klasa
InetAddress
je malo neobična jer nema ni jedan public
konstruktor. Umjesto toga ime hosta ili dotted quad adresu u string
formatu prosljeđujete statičkoj metodi InetAddress.getByName()
kao u sljedećem primjeru:
try {InetAddress public = InetAddress.getByName("public.srce.hr");
InetAddress jagor = InetAddress.getByName("161.53.2.130");
}catch (UnknownHostException e) { System.err.println(e);} Neki
hostovi imaju više adresa. Ako pretpostavljate da je to slučaj sa hostom kojeg
ispitujete, možete dobiti polje objekata tipa InetAddress
pomoću statičke metode InetAddress.getAllByName(),
na primjer ovako:
import
java.net.*;
public class HostAddresses
{
public static void main (String args[])
{
try {
InetAddress[]
addresses = InetAddress.getAllByName(args[0]);
for (int i = 0;
i < addresses.length; i++) {
System.out.println(addresses[i]);
}
}
catch (UnknownHostException
e)
{
System.out.println("Ne mogu naci trazeni host");
}
catch
(ArrayIndexOutOfBoundsException e) {
System.out.println("Upisite ime trazenog hosta");
}
}
}
Imat ćemo:
% javac HostAddresses.java% java HostAddresses student.math.hrstudent.math.hr/161.53.8.14student.math.hr/161.53.29.70%Konačno,
statička metoda InetAddress.getLocalHost()
vraća objekt tipa InetAddress
koji sadrži adresu računala na kojem se program izvršava:
try {InetAddress me = InetAddress.getLocalHost();
}catch (UnknownHostException e) { System.err.println(e);}
Za
objekt tipa InetAddress
možete dobiti ime hosta kao string, IP adresu kao string ili kao polje byteova,
a također možete ispitati je li to tzv. multicast adresa (adresa klase D,
čija su prva četiri bita 1110). To se rješava sljedećim metodama:
public String getHostName()public String getHostAddress()public byte[] getAddress()public boolean isMulticastAddress()Sljedeći program ispisuje podatke o lokalnom hostu.
import
java.net.*;
public class LocalHost
{
public static void main(String[] args)
{
try {
InetAddress me =
InetAddress.getLocalHost();
System.out.println("Ime lokalnog hosta
----->
" +
me.getHostName());
System.out.println("Adresa lokalnog hosta
---> " +
me.getHostAddress());
byte[] address =
me.getAddress();
System.out.print("Adresa po byteovima -----> ");
for (int i = 0;
i < address.length; i++) {
System.out.print(address[i] + " ");
}
System.out.println();
if
(me.isMulticastAddress())
System.out.println("multicast");
else
System.out.println("nije multicast");
}
catch (UnknownHostException
e) {
System.err.println("Ne mogu naci trazeni host");
}
}
}
% javac LocalHost.java% java LocalHostIme lokalnog hosta -----> student.math.hrAdresa lokalnog hosta ---> 161.53.8.14Adresa po byteovima -----> -95 53 8 14nije multicast%
Primijetite
da su byteovi koje vraća metoda getAddress()
označeni iako se, prema konvenciji, za dotted quad adrese koriste
neoznačeni byteovi.
URL, kratica za "Uniform Resource Locator", je način za jednoznačno identificiranje lokacije nekog resursa na internetu. Tipični URL-ovi izgledaju ovako:
http://public.srce.hr/file:///Macintosh%20HD/Java/Docs/JDK%201.1.1%20docs/api/java.net.InetAddress.html#_top_http://www.macintouch.com:80/newsrecent.shtmlftp://ftp.carnet.hr/pub/mailto:Mladen.Vedris@student.math.hrtelnet://student.math.hrVećina URL-ova može se rastaviti na sljedeće komponente (koje ne moraju sve biti prisutne u svakom URL-u):
URLURL-ovi
su u Javi predstavljeni klasom java.net.URL.
Postoje konstruktori za kreiranje novog URL-a i metode za parsiranje različitih
dijelova URL-a. Ipak, bitni dio ove klase su metode koje vam omogućuju da sa
nekog URL-a dobijete InputStream
i na taj način čitate podatke s poslužitelja.
Klasa
URL
usko je povezana s handlerima protokola i sadržaja. Cilj je odvojiti
snimljene (downloaded) podatke od protokola koji je korišten za njihovo
snimanje. Handler protokola je odgovoran za komuniciranje sa poslužiteljem, tj.
prenošenje byteova od poslužitelja do klijenta. On obavlja potrebne “pregovore”
(negotiations) oko poslužitelja i svih potrebnih headera. Njegov je posao
dobaviti byteove traženih podataka. Handler sadržaja preuzima te byteove i
prevodi ih u neku vrstu Java objekta kao što je InputStream
ili ImageProducer.
Kad
konstruirate objekt tipa URL,
Java će potražiti handler protokola koji razumije “protokolski” dio URL-a, kao
što je npr. "http" ili "mailto". Ako ne pronađe takav handler, izbacit će
MalformedURLException.
Koji su protokoli podržani, ovisi o implementaciji, no http i file su podržani
uglavnom svagdje. Sun-ov JDK 1.1. razumije sljedećih deset:
Posljednjih pet su specifični Sun-ovi protokoli i koriste ih interno JDK i HotJava.
URL
objekataPogledajmo
neke od konstruktora klase URL.
Svi oni izbacuju MalformedURLException.
public URL(String u) throws MalformedURLExceptionpublic URL(String protocol, String host, String file) throws MalformedURLExceptionpublic URL(String protocol, String host, int port, String file) throws MalformedURLExceptionpublic URL(URL context, String u) throws MalformedURLExceptionZa
potpuni, apsolutni URL kao što je
http://student.math.hr/~vedris/java/java-predavanja/java-predavanje-01.htm
konstruirate odgovarajući URL
objekt ovako:
URL u = null; try {u = new URL("http://student.math.hr/~vedris/java/java-predavanja/java-predavanje-01.htm");
} catch (MalformedURLException e) { }You can also construct the URL by passing its pieces to the constructor, like this:
URL u = null; try { u = new URL("http", "student.math.hr", "~vedris/java/java-predavanja/java-predavanje-01.htm"); } catch (MalformedURLException e) { }U pravilu ne morate specificirati port za URL. Većina protokola ima pretpostavljeni (default) URL , pa tako za http pretpostavljamo 80. Međutim, ako tražimo nešto što nije na default portu, poslužit ćemo se trećim konstruktorom:
URL u = null; try {u = new URL("http", "student.math.hr",80,
"~vedris/java/java-predavanja/java-predavanje-01.htm"); } catch (MalformedURLException e) { }Konačno,
mnoge HTML datoteke sadrže relativne URL-ove. Na primjer, URL ove stranice je
http://student.math.hr/~vedris/java/java-predavanja/java-predavanje-12.htm
Ako bismo htjeli mirorirati ove stranice na nekom drugom računalu, mogli
bismo umjesto apsolutnih koristiti relativne URL-ove koji nasljeđuju ime hosta
itd.. Na primjer, ako na ovoj stranici imamo link java-predavanje-02,
onda on zapravo pokazuje na http://student.math.hr/~vedris/java/java-predavanja/java-predavanje-02.htm,
međutim, na računalu regoc.srce.hr
pokazivao bi na
http://regoc.srce.hr/~vedris/java/java-predavanja/java-predavanje-12.htm
i tako dalje. Četvrti od gore navedenih konstruktora kreira URL koji je
relativan u odnosu na zadani URL. Na primjer:
URL u1, u2; try { u1 = new URL("http://student.math.hr/~vedris/java/java-predavanja/java-predavanje-01.htm"); u2 = new URL(u1, "java-predavanje-02.htm"); } catch (MalformedURLException e) { }To je posebno korisni kod parsiranja HTML-a.
URL
objekataKlasa
java.net.URL
koristi sljedeće metode za rastavljanje URLa na njegove komponente:
public String getProtocol()public String getHost()public int getPort() public String getFile()public String getRef()Na primjer,
try { URL u = new URL("http://student.math.hr/~vedris/java/html/TricksterApplet.html#top"); System.out.println("Protokol: " + u.getProtocol()); System.out.println("Host : " + u.getHost()); System.out.println("Port : " + u.getPort()); System.out.println("File : " + u.getFile()); System.out.println("Anchor : " + u.getRef()); } catch (MalformedURLException e) { }Ako port u URLu nije eksplicitno specificiran, vraća se -1. To ne znači da se pokušava napraviti konekcija na (nepostojeći) port –1, nego jednostavno da se koristi default port.
Ako
ne postoji referenca (anchor), onda je ona naprosto null, pa treba
uhvatiti NullPointerException
ili, još bolje, ispitati da je non-null prije nego li je koristimo.
Konačno, ako je izostavljen file, kao na primjer u http://student.math.hr, odgovarajuća se vrijednost postavlja na "/".
Metoda
openStream()
otvara konekciju na poslužitelj kojeg URL specificira te vraća InputStream
s podacima iz te konekcije. To omogućuje snimanje podataka sa poslužitelja. Svi
headeri koji dolaze prije stvarnih podataka ili tražene datoteke bit će
obrisani prije nego stream bude otvoren. Dobit ćete samo čiste podatke.
public final InputStream openStream() throws IOException
Stream
ćete pročitati koristeći se metodama iz paketa java.io
o kojem smo govorili u desetom
predavanju. Primijetite da većina mrežnih konekcija predstavlja manje
pouzdan i sporiji izvor podataka nego što su to datoteke. Bit će dakle potrebno
izvršiti bufferiranje, koristeći se pri tom klasama BufferedInputStream
ili BufferedReader.
Program
iz sljedećeg primjera čita niz URLa sa komandne linije. Iz svakog argumenta
pokušava formirati URL, povezati se na specificirani poslužitelj i snimiti
podatke koje će onda ispisati na System.out.
import java.net.*;import java.io.*; public class Webcat { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { URL u = new URL(args[i]); InputStream is = u.openStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String theLine; while ((theLine = br.readLine()) != null) { System.out.println(theLine); } } catch (MalformedURLException e) { System.err.println(e); } catch (IOException e) { System.err.println(e); } } } }% javac Webcat.java
% java Webcat "http://student.math.hr/~vedris/java/html/TricksterApplet.html"
<APPLET CODE="TricksterApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="Trickster.jar"
WIDTH=1 HEIGHT=1>
</APPLET>
%
Prije nego se podaci šalju preko Interneta s jednog hosta na drugi uz pomoć TCP/IP, oni se pakiraju u pakete različitih, ali konačnih veličina koji se nazivaju datagrami. Veličina datagrama varira od nekoliko desetaka byteova pa do oko 60,000 byteova. Sve što je veće od toga, a često i ono što je manje od toga, treba podijeliti u manje dijelove prije odašiljanja. Prednost takvog slanja podataka je u tome što ako se jedan paket putem izgubi, on se može poslati ponovo bez da se opet šalju svi ostali paketi. Također, ako paketi stignu izvan poretka, oni se mogu pravilno poredati i kod primatelja.
Ipak, sve je ovo transparentno za Java programera. Hostov ugrađeni mrežni softver će transparentno obaviti razdiobu podataka u pakete na strani pošiljatelja te ih ponovo spojiti na strani primatelja. Umjesto toga, Java programer se susreće s vrlo visokom apstrakcijom koju nazivamo utičnica (socket). Utičnica predstavlja pouzdanu konekciju za prijenos podataka između dva hosta. Ona vas izolira od detalja kodiranja paketa, gubitka i ponovnog slanja pošiljki, te uspostavljanja poretka među pristiglim paketima.
Utičnica obavlja sljedeće četiri fundamentalne operacije:
Utičnica ne može biti priključena na više hostova istodobno.
SocketKlasa
java.net.Socket
omogućuje izvođenje svih četiriju fundamentalnih operacija na utičnicama. Možete
ostvariti konekciju na udaljeno računalo, slati i primati podatke te prekinuti
konekciju.
Konekcija
se obavlja uz pomoć konstruktora. Svakom objektu tipa Socket
pridružen je točno jedan udaljeni host. Da biste ostvarili konekciju na drugi
host, morate kreirati novi objekti tipa Socket.
public Socket(String host, int port) throws UnknownHostException, IOExceptionpublic Socket(InetAddress address, int port) throws IOExceptionpublic Socket(String host, int port, InetAddress localAddress, int localPort) throws IOExceptionpublic Socket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOExceptionSlanje i primanje podataka obavlja se pomoću izlaznih i ulaznih streamova. Sljedeće metode daju odgovarajuće streamove za danu utičnicu.
public InputStream getInputStream() throws IOExceptionpublic OutputStream getOutputStream() throws IOExceptionSljedeća metoda zatvara utičnicu:
public synchronized void close() throws IOExceptionPostoji i nekoliko metoda koje postavljanju različite opcije vezane uz utičnicu, no uglavnom ćete otkriti da su default vrijednosti sasvim zadovoljavajuće.
public void setTcpNoDelay(boolean on) throws SocketExceptionpublic boolean getTcpNoDelay() throws SocketExceptionpublic void setSoLinger(boolean on, int val) throws SocketExceptionpublic int getSoLinger() throws SocketExceptionpublic synchronized void setSoTimeout(int timeout) throws SocketExceptionpublic synchronized int getSoTimeout() throws SocketExceptionpublic static synchronized void setSocketImplFactory(SocketImplFactory fac) throws IOExceptionSljedeće metoda daju različite informacije o utičnici:
public InetAddress getInetAddress()public InetAddress getLocalAddress()public int getPort()public int getLocalPort()Na
kraju, tu je i uobičajena toString()
metoda:
public String toString()
Socket
objekataPogledajmo
public,
non-deprecated konstruktore klase Socket.
public Socket(String host, int port) throws UnknownHostException, IOExceptionpublic Socket(InetAddress address, int port) throws IOExceptionpublic Socket(String host, int port, InetAddress localAddr, int localPort) throws IOExceptionpublic Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOExceptionPotrebno
je, dakle, specificirati u najmanju ruku host i port na koji se želite
konektirati. Host može biti specificiran bilo kao string, npr "student.math.hr"
ili kao objekt tipa InetAddress.
Port mora biti cijeli broj između 1 i 65535. Ne može biti bilo koji, već ga
trebate znati isto kao i ime hosta. Na primjer,
Socket webStudent = new Socket("student.math.hr", 80); Posljednja
dva konstruktora također specificiraju host i port sa kojega ostvarujete
konekciju. Na sistemu sa više IP adresa, kao što su mnogi web poslužitelji, to
vam omogućuje da odaberete svoje mrežno sučelje i IP adresu. Možete
specificirati i broj porta, ali kako svaki pojedini port može biti zauzet,
najbolje je staviti port 0. To će reći sistemu da izabere bilo koji slobodni
port. Ako želite znati s kojeg porta ste napravili konekciju, pozvat ćete metodu
getLocalPort().
Socket webStudent = new Socket("student.math.hr", 80, "pc-mladen.srce.hr", 0); Ovi
konstruktori neće samo kreirati novi objekt tipa Socket.
Oni će također pokušati ostvariti konekciju na specificirani udaljeni
poslužitelj. Svi oni zato odbacuju IOException u
slučaju da se konekcija iz bilo kojeg razloga ne može uspostaviti.
Ne možete se naprosto konektirati na bilo koji port na bilo kojem hostu. Konekcija je moguća samo na one portove na kojima udaljeno računalo osluškuje dolazne konekcije. Konstruktore utičnica možete koristiti da biste ustanovili na kojim portovima računalo osluškuje. Pogledajte primjer:
import java.net.*;import java.io.IOException; public class PortScanner { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { InetAddress ia = InetAddress.getByName(args[i]); scan(ia); } catch (UnknownHostException e) { System.err.println(args[i] + " is not a valid host name."); } } } public static void scan(InetAddress remote) { // Do I need to synchronize remote? // What happens if someone changes it while this method // is running? String hostname = remote.getHostName(); // Skanirat cemo samo portove od 78 do 81. // Potpuno skaniranje islo bi od 0 do 65535. Ne cinite to bez dozvole vlasnika hosta! for (int port = 78; port < 82; port++) { try { Socket s = new Socket(remote, port); System.out.println("Server slusa na portu " + port + " racunala " + hostname); s.close(); } catch (IOException e) { System.out.println("Racunalo ne slusa na portu " + port); } } } public static void scan(String remote) throws UnknownHostException { // Why throw the UnknownHostException? Why not catch it like I did // in the main() method? InetAddress ia = InetAddress.getByName(remote); scan(ia); } }
Izvršit ćemo ovu ograničenu verziju PortScannera koja ispituje samo portove od 78 do 81. Primijetit ćete da računalo sluša na portu 80. To je standardni port za web poslužitelj.
% javac PortScanner.java
% java PortScanner localhost
Racunalo ne slusa na portu 78
Racunalo ne slusa na portu 79
Server slusa na portu 80 racunala localhost
Racunalo ne slusa na portu 81
%
Upozorenje: Ne pokušavajte usmjeriti kompletni
PortScanner prema mašini koja nije vaša vlastita bez dozvole vlasnika /
sistem inženjera, jer će se to smatrati hakerskim napadom i ugrožavanjem
sigurnosti računala!!!
Jednom kad je utičnica konektirana, možete slati podatke na poslužitelj putem izlaznog streama ili ih primati sa poslužitelja pomoću ulaznog streama. Koje točno podatke šaljete ili primate obično ovisi o protokolu.
Metoda
getInputStream()
vraća objekt tipa InputStream
koji čita podatke iz utičnice. Možete koristiti uobičajene metode klase
InputStream
o kojima ste učili u desetom
predavnju. Uglavnom će biti potrebno povezati InputStream
sa nekim drugim ulaznim streamom ili readerom kako bi se lakše moglo rukovati
podacima.
Na primjer, sljedeći fragment koda radi konekciju na daytime poslužitelj na portu 13 računala student.math.hr i ispisuje podatke koje od njega dobije.
try { Socket s = new Socket("student.math.hr", 13); InputStream is = s.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String theTime = br.readLine(); System.out.println(theTime); } catch (IOException e) { return (new Date()).toString(); }
Pogledajmo sada kompletan program, Daytime klijent, koji se konektira na daytime poslužitelj računala student.math.hr na portu 13 i ispisuje podatke koje od njega dobije.
import java.net.*;import java.io.*;import java.util.Date; public class Daytime { InetAddress server; int port = 13; public static void main(String[] args) { try { Daytime d = new Daytime("student.math.hr"); System.out.println(d.getTime()); } catch (IOException e) { System.err.println(e); } } public Daytime() throws UnknownHostException { this (InetAddress.getLocalHost()); } public Daytime(String name) throws UnknownHostException { this(InetAddress.getByName(name)); } public Daytime(InetAddress server) { this.server = server; } public String getTime() { if (server == null) return (new Date()).toString(); try { Socket s = new Socket(server, port); InputStream is = s.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); StringBuffer sb = new StringBuffer(); String theLine; while ((theLine = br.readLine()) != null) { sb.append(theLine + "\r\n"); } return sb.toString(); } catch (IOException e) { return (new Date()).toString(); } } }% javac Daytime.java
% java Daytime
Tue Jan 22 16:16:31 MET 2002
%
Metoda
getOutputStream()
vraća objekt tipa OutputStream
pomoću kojeg se ispisuju podaci na utičnicu. Možete koristiti sve uobičajene
metoed klase OutputStream
o kojima ste učili u desetom
predavanju. Uglavnom će biti potrebno povezati OutputStream
sa nekim drugim izlaznim streamom ili readerom kako bi se lakše moglo rukovati
podacima.
Na
primjer, sljedeći program se konektira na discard poslužitelj na portu 9
računala student.math.hr
i šalje mu podatke koje čita sa standardnog ulaza System.in.
byte[] b = new byte[128]; try { Socket s = new Socket("student.math.hr", 9);OutputStream out =s.getOutputStream();
while (true) { int n = System.in.available(); if (n > b.length) n = b.length; int m = System.in.read(b, 0, n); if (m == -1) break; out.write(b, 0, n); } s.close(); } catch (IOException e) { }
Pogledajmo
sada kompletan program, Discard
klijent, koji se konektira na Discard poslužitelj računala student.math.hr
na portu 9 i šalje mu podatke koje čita sa standardnog ulaza System.in.
import java.net.*;import java.io.*; public class Discard extends Thread { InetAddress server; int port = 9; InputStream theInput; public static void main(String[] args) { try { Discard d = new Discard("student.math.hr"); d.start(); } catch (IOException e) { System.err.println(e); } } public Discard() throws UnknownHostException { this (InetAddress.getLocalHost(), System.in); } public Discard(String name) throws UnknownHostException { this(InetAddress.getByName(name), System.in); } public Discard(InetAddress server) { this(server, System.in); } public Discard(InetAddress server, InputStream is) { this.server = server; theInput = System.in; } public void run() { byte[] b = new byte[128]; try { Socket s = new Socket(server, port);OutputStream out =s.getOutputStream();
while (true) { int n = theInput.available(); if (n > b.length) n = b.length; int m = theInput.read(b, 0, n); if (m == -1) break; out.write(b, 0, m); } s.close(); } catch (IOException e) { } } }% javac Discard.java
% java Discard
asdf
<Ctrl-C>
%
Nije uobičajeno da se s utičnice samo čita ili da se na nju samo piše. Većina protokola traži da klijent i čita i piše. Neki protokoli traže da čitanje i pisanje bude naizmjenično, npr.
write
read
write
read
write
read
Drugi protokoli, npr. HTTP 1.0, traže višestruke ispise nakon kojih slijede višestruka čitanja, npr.:
write
write
write
read
read
read
read
Neki protokoli dozvoljavaju da klijentovi upiti i poslužiteljevi odgovori budu slobodno izmiješani.
Java ne stavlja nikakve restrikcije na čitanje i pisanje po utičnicama. Jedan thread može čitati s utičnice, a drugi može po njoj istodobno pisati. (Primijetite da to nije isto kao kad jedan thread čita datoteku, a drugi piše u nju.)
Program u sljedećem primjeru šalje upit HTTP poslužitelju koristeći izlazni stream utičnice, a zatim čita odgovor koristeći ulazni stream utičnice. HTTP poslužitelji sami zatvaraju konekciju kad pošalju odgovor.
import java.net.*;import java.io.*; public class Grabber { public static void main(String[] args) { int port = 80; for (int i = 0; i < args.length; i++) { try { URL u = new URL(args[i]);