Mrezno Programiranje

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 43

143

Poglavlje 3
Mreno programiranje

Povezivanje na server
Implementacija
Slanje elektronske pote (e-mail)
Pravljenje URL veza
Napredno Socket programiranje

Zapoinjemo ovo poglavlje pregledom osnovnih koncepata umreivanja. Zatim


prelazimo na pisanje Java programa koji se povezuju na mrene servise. Pokazaemo
vam kako da dobijete informaciju sa web servera i kako se alje e-mail iz Java programa.
Zavravamo poglavlje sa detaljnim pregledom koji kombinuje applet i servlet da bi se
sakupile informacije sa Internet-a.
U prvom delu ovog poglavlja pretpostavljamo da nemate iskustva u mrenom
programiranju. Ako ste ve pisali TCP/IP programe i port-ovi i socket-i nisu misterija za
vas, trebalo bi da preletite kroz primere koda. Pri kraju ovog poglavlja, kod postaje
kompleksan i namenjen je onima sa vie iskustva u mrenom programiranju.

Povezivanje na Server
Pre pisanja naeg prvog mrenog programa, nauimo neto o monom alatu za
otklanjanje greaka (debugging) u mrenom programiranju, naime o telnet-u. Telnet je
ve instaliran na veini sistema ( i u UNIX-u i u Windows-u). Trebalo bi da moe da se
pokrene kucanjem telnet u command shell-u.
Moda ste ve koristili telnet da se poveete sa udaljenim raunarom, ali moete ga
koristiti za komunikaciju sa drugim servisima to omoguuju Internet host-ovi, takoe.
Evo primera ta se moe uraditi. Kucajte:
telnet time-A.timefreq.bldrdoc.gov 13

Kao to slika 3-1 pokazuje, trebalo bi da se prikae ova linija:


52088 01-06-28 14:35:13 50 0 0 644.8 UTC(NIST) *

144

Slika 3-1: Izlaz servisa '' time of day''


ta se deava? Povezali ste se na '' time of day'' servis koji veina UNIX maina stalno
izvravaju. Odreeni server za koji ste se povezali odrava Nacionalni Institut za
Standarde i Tehnologiju u Boulder-u, Colorado, i daje mere Cesiumskog atomskog sata.
(Naravno, prijavljeno vreme nije u potpunosti tano zbog mrenog odlaganja.)
Po konvenciji, ''time of day'' je uvek povezan na port 13.
NAPOMENA: U mrenom nainu govora, port nije fiziki ureaj, ve
apstrakcija koja olakava komunikaciju izmeu servera i klijenta (videti Sliku 32).

Slika 3-2: Povezivanje klijenta na port server.

145

Serverski softver neprekidno radi na udaljenoj maini, ekajui na bilo koji mreni
promet koji zahteva interakciju sa portom 13. Kada operativni sistem na udaljenom
raunaru primi mreni paket koji sadri zahtev da se povee sa portom 13, startuje se
serverski proces za ekanje i uspostavlja se veza. Veza se odrava dok je ne prekine jedna
od strana.
Kad ste poeli telnet sesiju sa time-A.timefreq.bldrdoc.gov 13 na portu 13, nepovezani
deo mrenog softvera je imao dovoljno informacija da konvertuje nisku ''timeA.timefreq.bldrdoc.gov 13'' u njenu tanu Internet Protocol adresu 132.163.4.104. Onda
softver alje zahtev tom raunaru, traei vezu sa portom 13. Jednom kada je veza
uspostavljena, udaljeni program alje nazad liniju informacija i onda prekida vezu.
Naravno, klijenti i serveri ulaze u iri dijalog pre nego to jedan od njih ne prekine vezu.
Evo jo jednog eksperimenta, uz iste linije, koje su malo interesantnije. Uradite sledee:
1. Iskoristite telnet da se poveete na java.sun.com na portu 80.
2. Kucajte sledee, tano kako pie, bez kucanja backspace-a. Primetite da ima
belina oko prve kose crte ali ne i oko druge.
3. GET / HTTP/1.0
4. Sada, pritisnite ENTER dva puta.
Slika 3-3 daje odgovor. Trebalo bi da izgleda iole poznato dobili ste HTML stranu
formatirani tekst, tj. glavnu web stranu za Java tehnologiju.
To je potpuno isti proces kroz koji va web pretraiva prolazi da bi doao do web strane.
Jedina razlika je to pretraiva prikazuje HTML kod u lepim fontovima.

Slika 3-3: Upotreba telnet-a za pristup HTTP portu

146
Na prvi mreni program u primeru 3-1 e uraditi istu stvar koja je odraena korienjem
telnet-veze na port i tampanja pronaenog.
Primer 3-1: SocketTest.java
import java.io.*;
import java.net.*;
import java.util.*;
/**
Program pravi socket vezu sa atomskim satom u Boulder-u,Colorado i prikazuje vreme koje
salje server.
*/
public class SocketTest
{
public static void main(String[] args)
{
try
{
Socket s = new Socket("time-A.timefreq.bldrdoc.gov", 13);
try
{
InputStream inStream = s.getInputStream();
Scanner in = new Scanner(inStream);
while (in.hasNextLine())
{
String line = in.nextLine();
System.out.println(line);
}
}
finally
{
s.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

Komande za ovaj jednostavan program su sledee:


Socket s = new Socket(''time-A.timefreq.bldrdoc.gov'', 13);
InputStream inStream = s.getInputStream();

Prva linija otvara socket, apstraktan za mreni softver koji omoguava komunikaciju iz i
u taj program. Prosleujemo udaljenu adresu i broj porta konstruktoru socket-a. Ukoliko
veza ne uspe, onda se UnknownHostException prijavljuje. Ako postoji jo neki problem,
onda se javlja IOException. Zbog toga to je UnknownHostException podklasa
IOException i zato to je ovo uzorak programa, hvatamo samo nadklasu.
Jednom kada se socket otvori, metod getInputStream() u java.net.Socket vraa objekat
InputStream koji moete koristiti kao i bilo koji drugi tok. (Vidite deo 1, poglavlje 12 za
informacije o tokovima.) Jednom kada ste uhvatili tok, program jednostavno:

147
1. Koristi Scanner da proita liniju karaktera koju alje server; i
2. tampa svaku liniju na standardni izlaz.
Ovaj proces se nastavlja sve dok se tok ne zavri i server se ne diskonektuje.
NAPOMENA: Ovaj program radi samo sa vrlo jednostavnim
serverima, kao to je ''time of day'' servis. U neto kompleksnijem
mrenom programu, klijent alje zahtev serveru, i server ne mora
odmah da se iskljui na kraju odgovora. Videete kako moete da
implementirate ponaanje nekoliko primera kroz ovo
poglavlje.
Socket klasa je prijatna i laka za upotrebu zato to Java tehnologija krije sloenosti
uspostavljanja mrene veze i slanja podataka preko iste. Java.net paket daje isti
neophodni programski interfejs koji bi ste koristili kada bi ste radili sa fajlovima.

java.net.Socket

1.0

Socket(String host, int port)

pravi socket koji se povezuje na dati host i port.

InputStream getInputStream()
OutputStream getOutputStream()

preko tokova ita podatke od socketa i pie podatke na socket

Implementacija servera
Sada kada smo implementirali osnove mrenog klijenta koji prima podatke sa Interneta,
implementirajmo jednostavan server koji moe poslati informaciju klijentima. Jednom
kada pokrenete server program on eka nekog klijenta da se povee na njegov port.
Izabrali smo port 8189 koji ne koristi nijedan od standardnih servisa. ServerSocket klasa
uspostavlja socket. U naem sluaju, komanda:
ServerSocket s = new ServerSocket(8189);

uspostavlja server koji nadgleda port 8189. Komanda:


Socket incoming = s.accept();

Kae programu da neogranieno eka dok se klijent ne povee na taj port. Jednom kada
se neko povee na taj port slanjem tanog zahteva preko mree, ovaj metod vraa Socket
objekat koji predstavlja vezu koja je stvorena. Moete koristiti ovaj objekat da bi dobili
ulazne i izlazne tokove, kako je pokazano u sledeem kodu:
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();

Sve to server alje izlaznom toku servera postaje ulaz klijent programa, i ceo izlaz
klijent programa zavrava u ulaznom toku servera.
U svim primerima ovog poglavlja, prenosiemo tekst preko socketa. Zbog toga
prebacujemo tokove u skenere i pisae.
Scanner in = new Scanner(inScream);
PrintWriter out = new PrintWriter(outStream, true /* autoFlush */);

Poaljimo klijentu pozdrav:


Out.println(''Hello! Enter BYE to exit.'');

148
Kada koristite telnet da uspostavite vezu sa server programom na portu 8189, videete
prethodni pozdrav na terminalu.
U ovom jednostavnom serveru mi samo itamo samo ulaz klijenta, liniju po liniju i takve
ih tampamo. Ovo pokazuje da program prima ulazni tok klijenta. Aktuelni server bi
oigledno izraunao i vratio odgovor koji zavisi od ulaza.
String line = in.readLine();
if (line != null)
{
out.println("Echo: " + line);
if (line.trim().equals("BYE")) done = true;
}
else done = true;

Na kraju, zatvaramo dolazei socket.


incoming.close();

To je sve to ima o tome. Svaki, serverski program, kao to je HTTP web server nastavlja
sa izvoenjem skoka:
1. Prima naredbu od klijenta(''nabavi mi ovu informaciju'') preko dolazeeg toka
informacija.
2. Prima informaciju.
3. alje informaciju klijentu preko odlazeeg toka informacija.
Primer 3-2 je kompletan program.
Primer 3-2: EchoServer.java
import java.io.*;
import java.net.*;
import java.util.*;
/**
Program implementira jednostavan server koji slusa port 8189 i prikazuje sav klijentov unos
*/
public class EchoServer
{
public static void main(String[] args )
{
try
{
// Uspostavlja server socket
ServerSocket s = new ServerSocket(8189);
// Ceka na klijentovo povezivanje
Socket incoming = s.accept( );
try
{
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
Scanner in = new Scanner(inStream);
PrintWriter out = new PrintWriter(outStream, true /* autoFlush */);
out.println( "Hello! Enter BYE to exit." );
// Prikazuje klijentov unos
boolean done = false;
while (!done && in.hasNextLine())

149
{
String line = in.nextLine();
out.println("Echo: " + line);
if (line.trim().equals("BYE"))
done = true;
}
}
finally
{
incoming.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

Da bi probali, kompajlirate i pokrenite program. Onda, iskoristite telnet da se poveete na


sledei server i port:
Server: 127.0.0.1
Port: 8189
Ip adresa 127.0.0.1 je specijalna adresa, lokalna loopback adresa, koja obeleava lokalnu
mainu. Zbog toga to izvravate echo server lokalno, to je mesto gde elite da se
poveete.
Ako ste povezani direktno na Internet, tada bilo ko u svetu moe pristupiti vaem echo
serveru, ukoliko znaju vau IP adresu i broj porta.
Kada se poveete na port, videete poruku prikazanu na slici 3-4:
Hello! Enter BYE to exit.
Otkucajte bilo ta i gledajte ulazni echo na vaem ekranu. Otkucajte BYE (sve velikim
slovima) da se diskonektujete. Server program e se zatvoriti takoe.

150
Slika 3-4: Pristup echo serveru

java.net.ServerSocket 1.0

ServerSocket(int port)
kreira ServerSocket koji nadgleda port.
Socket accept()
eka na vezu. Ova metoda blokira tekuu nit dok se veza ne ostvari. Metoda vraa
Socket objekat kroz koji program moe da komunicira sa klijentom koji se
povezuje.
void close()
zatvara server socket.

Usluivanje vie klijenata


Postoji problem sa jednostavnim serverom u sledeem primeru. Pretpostavimo da elimo
da dozvolimo da se vie klijenata povee na na server u isto vreme. Tipino, server
neprestano radi na server raunaru i klijenti preko celog Interneta e moda eleti da
koriste server u isto vreme. Odbijanje viestrukih veza dozvoljava bilo kom klijentu da
monopolizuje servis povezivanjem na njega due vreme. Moemo raditi mnogo bolje
pomou niti.
Svaki put kada znamo da je program uspostavio novu socket vezu tj. da je poziv da za
prihvatanje uspean, mi emo pokrenuti novu nit koja e se pobrinuti za vezu izmeu
servera i odreenog klijenta. Glavni program e se samo vratiti i saekati novu vezu. Da
bi se ovo ostvarilo, glavni skok servera treba da izgleda ovako:
while (true)
{
Socket incoming = s.accept();
Runnable r = new ThreadedEchoHandler(incoming);
Thread t = new Thread(r);
t.start();
}

ThrededEchoHandler klasa implementira Runnable i sadri obavetajni skok sa

klijentom u njegovoj pozivnoj metodi.


class ThreadedEchoHandler implements Runnable
{ . . .
public void run()
{
try
{
InputStream inStream = incoming.getInputStream();
OutpurStream outStream = incoming.getOutputStream();
Process input and send response
incoming.close();
}
catch(Exception e)

151
{
handle exception
}
}
}

Zbog toga to svaka veza zapoinje novu nit, vie klijenata se moe povezati na server u
isto vreme. Ovo se moe lako proveriti. Kompajlirajte i izvrite server program (Primer
3-3). Otvorite nekoliko telnet prozora kao to je prikazano na slici 3-5. Moete
komunicirati kroz sve njih simultano. Server program se nikada ne gasi. Koristite
CTRL+C da ga ugasite.
Slika 3-5: Nekoliko telnet prozora koji komuniciraju simultano.
NAPOMENA: U ovom programu, stvaramo odvojene niti za svaku vezu.
Ovakav pristup nije zadovoljavajui za servere visokih performansi. Moete
postii veu propusnost koristei mogunosti java.nio paketa. Vidite http://www106.ibm.com/developerworks/java/library/j-javaio za vie informacija
Primer 3-3: ThreadedEchoServer.java
import java.io.*;
import java.net.*;
import java.util.*;
/**
Program implementira vie-nitni server koji slua port 8189 i prikazuje klijentov unos
*/
public class ThreadedEchoServer
{
public static void main(String[] args )
{
try
{
int i = 1;
ServerSocket s = new ServerSocket(8189);
while (true)
{

Socket incoming = s.accept();


System.out.println("Spawning " + i);
Runnable r = new ThreadedEchoHandler(incoming, i);
Thread t = new Thread(r);
t.start();
i++;
}
}
catch (IOException e)
{
e.printStackTrace();
}

152
}
}
/**
Ova klasa manipulie sa klijentovim unosom za jedan server socket.
*/
class ThreadedEchoHandler implements Runnable
{
/**
Konstruie manipulator
Parametar i je dolazei socket
Parametar c je broja manipulatora(koristi se u nalozima)
*/
public ThreadedEchoHandler(Socket i, int c)
{
incoming = i; counter = c;
}
public void run()
{
try
{
try
{
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
Scanner in = new Scanner(inStream);
PrintWriter out = new PrintWriter(outStream, true /* autoFlush */);
out.println( "Hello! Enter BYE to exit." );
// Prikazuje klijentov unos
boolean done = false;
while (!done && in.hasNextLine())
{
String line = in.nextLine();
out.println("Echo: " + line);
if (line.trim().equals("BYE"))
done = true;
}
}
finally
{
incoming.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private Socket incoming;
private int counter;
}

153

Slanje elektronske pote


U ovom delu, vam pokazujemo praktian primer socket programiranja: program koji alje
e-mail na udaljeni sajt.
Da bi ste poslali e-mail pravite socket vezu sa portom 25, SMTP port-om. SMTP je
Simple Mail Transport Protocol koji opisuje format za e-mail poruke. Moete se povezati
na bilo koji server koji radi pod SMTP servisom. Na UNIX mainama, taj servis je
obino implementiran pomou sendmail daemon-a (samostartujueg programa). tavie,
server mora da prihvati va zahtev. Ranije su sendmail serveri rutinski prihvatali da
prosleuju e-mailove od bilo koga, ali ovih dana zbog pretrpavanja spamovima, veina
servera ima ugraene provere i prihvata zahteve samo od korisnika, domena, ili IP adresa
kojima veruju.
Kada ste se povezali na server, poaljite mail zaglavlje (u SMTP formatu, koji je lak za
generisanje), praeno mail porukom.
Evo detalja:
1. Otvorite socket vaem host-u (domainu).
Socket s = new Socket("mail.yourserver.com", 25); // 25 is SMTP
PrintWriter out = new PrintWriter(s.getOutputStream());

2.

Poaljite sledeu informaciju na tok za pisanje:


HELO sending host
MAIL FROM: <sender email address>
RCPT TO: <recipient email address>
DATA
mail message
(any number of lines)
.
QUIT

SMTP specifikacija (RFC 821) naglaava da linije moraju biti zavrene sa \r praeno
sa \n.
Veina SMTP servera ne proverava verodostojnost informacija-moda ete moi da
snabdete bilo kog poiljaoca. (Imajte ovo na umu sledei put kada dobijete e-mail
poruku od president@whitehouse.gov koja vas poziva na zvanian dogaaj u glavnom
vrtu. Bilo ko je mogao da se povee na SMTP server i da kreira lanu poruku.)
Program u Primeru 3-4 je jednostavan e-mail program. Kao to moete da vidite na Slici
3-6, vi ukucavate poiljaoca, primaoca, mail poruke i SMTP server. Zatim kliknite na
dugme Send i vaa poruka je poslata.
Program jednostavno alje sekvencu naredbi o kojima je bilo rei. On prikazuje komande
koje alje SMTP serveru i obavetava kada su primljene. Imajte na umu da se
komunikacija sa mail serverom ostvaruje u posebnoj niti tako da korisniki interfejs niti
nije blokiran kada program pokua da se povee na mail server. (Vidite poglavlje 1 za
vie detalja o nitima u Swing aplikacijama.)

154

Slika 3-6: MailTest program


Primer 3-4: MailTest.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
/**
Program pokazuje kako mozemo da iskoristimo socket-e da bi poslali jednostavan tekst poruke.
*/
public class MailTest
{
public static void main(String[] args)
{
JFrame frame = new MailTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
/**
Okvir poruke GUI.
*/
class MailTestFrame extends JFrame
{
public MailTestFrame()
{
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
setTitle("MailTest");
setLayout(new GridBagLayout());
// Koristimo pogodnosti GBC klase iz Core Java Volume 1 Chapter 9

155
add(new JLabel("From:"), new GBC(0, 0).setFill(GBC.HORIZONTAL));
from = new JTextField(20);
add(from, new GBC(1, 0).setFill(GBC.HORIZONTAL).setWeight(100, 0));
add(new JLabel("To:"), new GBC(0, 1).setFill(GBC.HORIZONTAL));
to = new JTextField(20);
add(to, new GBC(1, 1).setFill(GBC.HORIZONTAL).setWeight(100, 0));
add(new JLabel("SMTP server:"), new GBC(0, 2).setFill(GBC.HORIZONTAL));
smtpServer = new JTextField(20);
add(smtpServer, new GBC(1, 2).setFill(GBC.HORIZONTAL).setWeight(100, 0));
message = new JTextArea();
add(new JScrollPane(message), new GBC(0, 3, 2, 1).setFill(GBC.BOTH).setWeight(100,
100));
comm = new JTextArea();
add(new JScrollPane(comm), new GBC(0, 4, 2, 1).setFill(GBC.BOTH).setWeight(100, 100));
JPanel buttonPanel = new JPanel();
add(buttonPanel, new GBC(0, 5, 2, 1));
JButton sendButton = new JButton("Send");
buttonPanel.add(sendButton);
sendButton.addActionListener(new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
new Thread(new
Runnable()
{
public void run()
{
comm.setText("");
sendMail();
}
}).start();
}
});
}
/**
Saljemo poruku koja je izradjena u GUI.
*/
public void sendMail()
{
try
{
Socket s = new Socket(smtpServer.getText(), 25);
InputStream inStream = s.getInputStream();
OutputStream outStream = s.getOutputStream();

156

in = new Scanner(inStream);
out = new PrintWriter(outStream, true /* autoFlush */);
String hostName = InetAddress.getLocalHost().getHostName();
receive();
send("HELO " + hostName);
receive();
send("MAIL FROM: <" + from.getText() + ">");
receive();
send("RCPT TO: <" + to.getText() + ">");
receive();
send("DATA");
receive();
send(message.getText());
send(".");
receive();
s.close();
}
catch (IOException e)
{
comm.append("Error: " + e);
}
}
/**
Salje nisku socket-u i prikazuje je u uobicajenom polju za tekst
Parametar s je niska koja se salje
*/
public void send(String s) throws IOException
{
comm.append(s);
comm.append("\n");
out.print(s.replaceAll("\n", "\r\n"));
out.print("\r\n");
out.flush();
}
/**
Dobija nisku od socket-a i prikazuje je u uobicajenom polju za tekst
*/
public void receive() throws IOException
{
if (in.hasNextLine());
{
String line = in.nextLine();
comm.append(line);
comm.append("\n");
}
}
private Scanner in;
private PrintWriter out;
private JTextField from;
private JTextField to;

157
private JTextField smtpServer;
private JTextArea message;
private JTextArea comm;
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 300;
}

Pravljenje URL veza


U poslednjem odeljku videli ste kako se koristi programiranje na nivou socketa da bi se
povezali na SMTP server i poslali e-mail. Ovo je dobro znati da bi se shvatila sutina
funkcionisanja e-mail servisa. tavie, ako planirate aplikaciju koja sadri e-mail,
verovatno ete eleti da radite na viem nivou i koristite biblioteku koja skriva detalje o
protokolu. Npr. Sun Microsystems je razvio JavaMail API kao standardnu ekstenziju Java
platforme. U JavaMail API jednostavno ete izdati zahtev kao to je:
Transport.send(message);

da bi ste poslali poruku. Biblioteka vodi rauna o protokolima poruke, viestrukim


primaocima, rukovodi dodacima (attachment), itd.
U ostatku ovog poglavlja, koncentrisaemo se na servise vieg nivoa koje standardno
izdanje Java platforme prua. Naravno, izvrna biblioteka koristi sockete da implementira
ove servise, ali ne morate brinuti o detaljima protokola kada koristite servise vieg nivoa.

URL i URI
URL i URLConnection klase skrivaju veinu kompleksnosti povratnih informacija sa

udaljenih sajtova. Moete konstruisati URL objekat niskom:


URL url = new URL(urlString);

Ako jednostavno elite da uhvatite sadraj izvora, onda moete koristiti openStream
metod URL klase. Ovaj metod stvara InputStream objekat. Koristite ga na uobiajen
nain, npr. da konstruiete Scanner:
InputStream inStream = url.openStream();
Scanner in = new Scanner(inStream);

Kao JDK 1.4, java.net paket pravi korisnu razliku izmeu URL-a (uniform resource
locators) i URI-a (uniform resource identifiers).
URI je isto sintaksike konstrukcije, koja odreuje razliite delove niske naglaavajui
web izvor. URL je posebna vrsta URI-a, naime ona sa dovoljno informacija da locira
izvor. Drugi URI kao to je:
mailto:cay@horstmann.com

nisu lokatori - nema podataka koje e identifikator locirati. Takav URI se naziva URN
(uniform resource name).
U Java biblioteci URI klasa nema metoda za pristup izvoru koji identifikator naglaava
sama njegova svrha je ralanjivanje. U suprotnom URL klasa moe otvoriti tok izvoru.
Zato, URL klasa radi samo sa shemama koje Java biblioteka prepoznaje, kao to su http:,
https:, ftp:, lokalni file system (file:) i JAR fajlovi (jar:).
Da bi videli zato ralanjivanje nije trivijalno uzmite u obzir koliko sloen URI moe
biti. Npr.
http://maps.yahoo.com/py/maps.py?csz=Cupertino+CA
ftp://username:password@ftp.yourserver.com/pub/file.txt

URI specifikacija daje pravila za izgled ovih identifikatora. URI ima sintaksu:

158
[scheme:]schemeSpecificPart[#fragment]

Npr. [...] obeleava opcioni deo i : i # su doslovno ukljueni u identifikator. Ako je


scheme: deo prisutan, URI se naziva apsolutnim. U suprotnom se naziva relativnim.
Apsolutni URI je opaque (neproziran,tup,neprovidan) ako schemeSpecificPart ne poinje
sa / kao npr.
mailto:cay@horstmann.com
Svi apsolutni nonopaque URI i relativni URI su hijerarhijski. Npr.
http://java.sun.com/index.html
../../java/net/Socket.html#Socket()

schemeSpecificPart hijerarhijskog URI-a ima strukturu:


[//authority][path][?query]

gde opet [...] oznaava opcioni deo.


Kod URI baziranog na serveru deo authority ima oblik:
[user-info@]host[:port]

Port mora biti ceo broj.


RFC 2396 koji standardizuje URI takoe podrava mehanizam baziran na registru po
kojem authority ima drugaiji format, ali oni nisu u uobiajenoj upotrebi.
Jedna od svrha URI klase je da ralani identifikator i razbije ga na njegove razliite
komponente. Moete ih povratiti metodama
getScheme
getSchemeSpecificPart
getAuthority
getUserInfo
getHost
getPort
getPath
getQuery
getFragment

Druga svrha URI klase je baratanje sa apsolutnim i relativnim identifikatorima. Ako


imate apsolutni URI kao to je:
http://docs.mycompany.com/api/java/net/ServerSocket.html

i relativni URI kao to je


../../java/net/Socket.html#Socket()

onda moete kombinovati ta dva u apsolutni URI.


http://docs.mycompany.com/api/java/net/Socket.html#Socket()

Ovaj proces se naziva reavanje relativnog URI-a.


Suprotni proces se naziva relativizacija. Npr. pretpostavite da imate osnovni URI
http://docs.mycompany.com/api

i URI
http://docs.mycompany.com/api/java/lang/String.html

Onda relativizacioni URI je


java/lang/String.html

URI klasa podrava obe od ovih operacija:


relative = base.relativize(combined);
combined = base.resolve(relative);

Upotreba URL veza za povratak informacija

159
Ako elite dodatne informacije o web izvoru onda bi trebalo da koristite URLConnection
klasu, koja vam daje mnogo vie kontrole nego osnovna URL klasa.
Kada radite sa URLConnection objektom, morate paljivo isplanirati vae korake, kao to
sledi:

1. Pozovite openConnection metod URL klase da bi odrali


objekat:

URLConnection

URLConnection connection = url.openConnection();

2. Setujte bilo koje zahtevane opcije, koristei metode:


setDoInput
setDoOutput
setIfModifiedSince
setUseCaches
setAllowUserInteraction
setRequestProperty

Diskutovaemo ove metode kasnije u ovom odeljku


i u API notacijama.
3. Poveite se na udaljeni izvor pozivanjem connect metode.
connection.connect();

Pored povezivanja socket vezom na server, ovaj


metod takodje pita server za informacije o
zaglavlju.
4. Nakon povezivanja na server, moete pozvati informaciju o zaglavlju. Dve
metode, getHeaderFieldKey i getHeaderField, nabrajaju sva polja zaglavlja. Kao
to JDK 1.4 metod getHeaderFields uzima standardni Map objekat koji sadri
polja zaglavlja. Radi vae ugodnosti, sledee metode pozivaju standardna polja.
getContentType
getContentLength
getContentEncoding
getDate
getExpiration
getLastModified

5. Konano, moete pristupiti izvoru podataka. Koristite getInputStream metod da


bi odrali ulazni tok za itanje informacija. (Ovo je isti ulazni tok koji vraa
openStream metod URL klase.) Drugi metod, getContent, nije veoma koristan u
praksi. Objekti koje vraaju standardni tipovi kao to su text/plain i image/gif
zahtevaju klase u com.sun hijerarhiji za procesiranje. Mogli bi da registrujete
vae sopstvene rukovodioce, ali mi ne diskutujemo o ovoj tehnici u ovoj knjizi.
UPOZORENJE: Neki programeri stvaraju pogrenu sliku kada koriste
URLConnection klasu i misle da getInputStream i getOutputStream metode
su sline sa onima iz Socket klase. Ali to nije ba tako. URLConnection
klasa radi mnogo ta iza scene, konkretno manipulisanje zahtevima i
odgovorima zaglavlja. Iz tog razloga, vano je pratite korake podeavanja
veze.

160

Pogledajmo detaljno neke URLConnection metode. Nekoliko metoda setuju osobine


veze pre povezivanja na server. Najvanije su setDoInput i setDoOutput. Standardno,
veza koristi ulazni tok za itanje sa servera, ali ne i izlazni tok za pisanje. Ako elite
izlazni tok (npr. za slanje podataka na web server), onda morate pozvati:
Connection.setDoOutput(true);

Dalje, moete da setujete neka zahtevana zaglavlja. Zahtevana zaglavlja se alju


zajedno sa zahtevnom komandom serveru. Evo primera:
GET www.server.com/index.html HTTP/1.0
Referer: http://www.somewhere.com/links.html
Proxy-Connection: Keep-Alive
User-Agent: Mozilla/4.76 (Windows ME; U) Opera 5.11 [en]
Host: www.server.com
Accept: text/html, image/gif, image/jpeg, image/png, */*
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: orangemilano=192218887821987

setIfModifiedSince metod govori vezi da ste zainteresovani za podatke koji su bili


promenjeni od odredjenog datuma. setUseCaches i setAllowUserInteraction su
korieni samo unutar apleta. setUseCaches metod upuuje pretraiva da prvo
proveri pretraivaki cache. setAllowUserInteraction metod dozvoljava apletu da se

pojavi u dialog box-u da bi se ispitalo korisniko ime i lozinka za zatiene izvore


(pogledajte Sliku 3-7). Ova setovanja nemaju efekta van apleta.

Slika 3-7: Dialog box sa mrenom lozinkom


Konano, moete koristiti catch-all setRequestProperty metod da setujete bilo koji
ime/vrednost par koji je znaajan za odreeni protokol. Za format HTTP zahtevanih
zaglavlja, pogledajte RFC 2616. Neki od ovih parametara nisu dobro dokumentovani i
prosleeni su okolo po usmenom dogovoru izmeu programera. Npr. ako elite da
pristupite zatienoj web strani, morate uraditi sledee.
1. Spojite korisniko ime, dvotaku i lozinku.
String input = username + ":" + password;

2. Procenite base64 kod rezultujue niske. (base64 kod kodira sled bajtova u sled
printabilnih ASCII karaktera.)
String encoding = base64Encode(input);

161
3. Pozovite setRequestProperty metod sa imenom "Authorization" i vrednou
"Basic" + kod:
connection.setRequestProperty("Authorization", "Basic " + encoding);

SAVET: Upravo ste videli kako pristupite ifrom-zatienoj web


strani. Da bi ste pristupili ifrom-zatienom podatku preko FTP-a,
koristite skroz drugaiji metod. Jednostavno konstruiete URL od
ftp://username:password@ftp.yourserver.com/pub/file.txt

Jednom kada pozovete connect metod, moete ispitati odgovor informacije zaglavlja.
Prvo, vidimo kako nabrajamo sve odgovore polja zaglavlja. Implementori ove klase su
osetili potrebu da izraze svoju individualnost upoznavajui nas sa jo jednim iteracionim
protokolom. Poziv
String key = connection.getHeaderFieldKey(n);

dobija n-ti klju od zaglavlja koje odgovara, gde n poinje od 1! Vraa null ako je n nula
ili vee od ukupnog broja polja zaglavlja. Ne postoji metod koji vraa broj polja;
jednostavno nastavite pozivanje getHeaderFieldKey dok ne dobijete null. Slino, poziv
String value = connection.getHeaderField(n);

vraa n-tu vrednost.


Po JDK 1.4, metod getHeaderFields vraa Map odgovor polja zaglavlja kome moete
pristupiti kao to je objanjeno u Poglavlju 2.
Map headerFields = connection.getHeaderFields();

Evo skupa odgovora polja zaglavlja od tipinog HTTP zahteva.


Date: Wed, 29 Aug 2001 00:15:48 GMT
Server: Apache/1.3.3 (Unix)
Last-Modified: Sun, 24 Jun 2001 20:53:38 GMT
ETag: "28094e-12cd-37729ad2"
Accept-Ranges: bytes
Content-Length: 4813
Connection: close
Content-Type: text/html

Kao pogodnost, est metoda nose vrednosti najeih tipova zaglavlja i prebacuje ih u
numerike tipove kada je to potrebno. Tabla 3-1 pokazuje ove pogodne metode. Metode
sa povratnim tipom long vraaju broj sekundi od Januara 1, 1970 GMT.
Program u Primeru 3-5 vam dozvoljava da eksperimentiete sa URL vezama. Obezbedite
URL i opciono korisniko ime i lozinku u komandnoj liniji kada izvravate program, npr.
java URLConnectionTest http://www.yourserver.com user pw

Table 3-1: Pogodne metode za odgovarajue vrednosti zaglavlja


Kljuno ime
Ime metoda
Tip koji se Vraa
Date
getDate
long
Expires
getExpiration
long

162
Last-Modified
Content-Length
Content-Type
Content-Encoding

getLastModified
getContentLength
getContentType
getContentEncoding

long
int
String
String

Ovaj program tampa


Sve kljueve i vrednosti zaglavlja;
Povratne vrednosti est pogodnih metoda u Tabli 3-1;
Prvih deset linija zahtevanog izvora.
Program je direktan, izuzev izraunavanja base64 koda. Postoji nedokumentovana klasa,
sun.misc.Base64Encode, koju moete koristiti umesto one koju smo naveli u Primer
programu. Jednostavno zamenite poziv na base64Encode sa
String encoding = new sun.misc.BASE64Encoder().encode(input.getBytes());

tavie, omoguili smo nau sopstvenu klasu zato to ne volimo da se pozivamo na klase
u sun ili com.sun paketima.
NAPOMENA: javax.mail.internet.MimeUtility klasa u standardnom dodatnom

pakovanju takoe ima metod za Base64 kodiranje. SDK 1.4 ukljuuje paket
koji sadri vidljivu (ne-javnu) klasu
java.util.prefs.Base64.

Primer 3-5: URLConnectionTest.java


import java.io.*;
import java.net.*;
import java.util.*;
/**
Program se povezuje na URL i prikazuje zaglavlje podataka za odgovore i prvih 10 linija
zahtevanih podataka
Snabdeva URL i opciono korisniko ime i sifru (za HTTP osnovno prepoznavanje) na komadnoj
liniji
*/
public class URLConnectionTest
{
public static void main(String[] args)
{
try
{
String urlName;
if (args.length > 0)
urlName = args[0];
else
urlName = "http://java.sun.com";
URL url = new URL(urlName);

163
URLConnection connection = url.openConnection();
// Postavlja korisnicko ime, sifru ako je naglaseno u komadnoj liniji
if (args.length > 2)
{
String username = args[1];
String password = args[2];
String input = username + ":" + password;
String encoding = base64Encode(input);
connection.setRequestProperty("Authorization", "Basic " + encoding);
}
connection.connect();
// Prikazuje polja zaglavlja
Map<String, List<String>> headers = connection.getHeaderFields();
for (Map.Entry<String, List<String>> entry : headers.entrySet())
{
String key = entry.getKey();
for (String value : entry.getValue())
System.out.println(key + ": " + value);
}
// Prikazuje pogodne funkcije
System.out.println("----------");
System.out.println("getContentType: " + connection.getContentType());
System.out.println("getContentLength: " + connection.getContentLength());
System.out.println("getContentEncoding: " + connection.getContentEncoding());
System.out.println("getDate: " + connection.getDate());
System.out.println("getExpiration: " + connection.getExpiration());
System.out.println("getLastModifed: " + connection.getLastModified());
System.out.println("----------");
Scanner in = new Scanner(connection.getInputStream());
// Prikazuje prvih deset linija sadrzaja
for (int n = 1; in.hasNextLine() && n <= 10; n++)
System.out.println(in.nextLine());
if (in.hasNextLine()) System.out.println(". . .");
}
catch (IOException e)
{
e.printStackTrace();
}
}
/**
Racuna Base64 kodirajuci nisku
Parametar s je niska
Vraca Base 64 kodiran sa s
*/
public static String base64Encode(String s)
{

164
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
Base64OutputStream out = new Base64OutputStream(bOut);
try
{
out.write(s.getBytes());
out.flush();
}
catch (IOException e)
{
}
return bOut.toString();
}
}
/**
Ovaj filter toka konvertuje tok bajtova u njihov Base63 kod
Base64 kod kodira 3 bajta u 4 karaktera.
|11111122|22223333|33444444|
svaki set ot 6 bita je kodiran prema Base64 mapi.
Ako broj unesenih bajtova nije deljiv sa 3, onda zadnje dve grupe od 4
karaktera padded sa jednim ili dva znaka =. Svaka izlazna linija ima najvise 76
karaktera.
*/
class Base64OutputStream extends FilterOutputStream
{
/**
Konstuise filter toka
Parametar out je tok filtera
*/
public Base64OutputStream(OutputStream out)
{
super(out);
}
public void write(int c) throws IOException
{
inbuf[i] = c;
i++;
if (i == 3)
{
super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
super.write(toBase64[((inbuf[0] & 0x03) << 4) | ((inbuf[1] & 0xF0) >> 4)]);
super.write(toBase64[((inbuf[1] & 0x0F) << 2) | ((inbuf[2] & 0xC0) >> 6)]);
super.write(toBase64[inbuf[2] & 0x3F]);
col += 4;
i = 0;
if (col >= 76)
{
super.write('\n');
col = 0;
}
}
}
public void flush() throws IOException
{

165
if (i == 1)
{
super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
super.write(toBase64[(inbuf[0] & 0x03) << 4]);
super.write('=');
super.write('=');
}
else if (i == 2)
{
super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
super.write(toBase64[((inbuf[0] & 0x03) << 4) | ((inbuf[1] & 0xF0) >> 4)]);
super.write(toBase64[(inbuf[1] & 0x0F) << 2]);
super.write('=');
}
}
private static char[] toBase64 =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
private int col = 0;
private int i = 0;
private int[] inbuf = new int[3];
}

NAPOMENA: esto postavljeno pitanje je da li Java platforma podrava pristup


obezbeenim web stranama (https: URL-ovi).Od JDK 1.4, SSL je deo standardne
biblioteke.
Pre JDK 1.4 mogli ste samo da napravite SSL vezu iz apleta tako
to iskoristite SSL implementaciju pretraivaa.
java.net.URL 1.0

InputString openStream()

otvara ulazni tok za itanje izvornih podataka.

URLConnection openConnection();

vraa URLConnection objekat koji radi sa vezom do izvora.


java.net.URLConnection 1.0

166

void setDoInput(boolean doInput)


boolean getDoInput()

ako je doInput taan, onda korisnik moe primiti ulaz sa ove URLConnection.

void setDoOutput(boolean doOutput)


boolean getDoOutput()

ako je doOutput taan, onda korisnik moe poslati izlaz ovoj URLConnection

void setIfModifiedSince(long time)


long getIfModifiedSince()

ifModifiedSince opcija odreuje ovu URLConnection da uhvati samo one podatke


koji su bili promenjeni od datog datuma. Ovo vreme je dato u sekundama od ponoi,
GMT, 1. Januar , 1970.
void setUseCaches(boolean useCaches)
boolean getUseCaches()

ako je UseCaches taan, onda podaci mogu biti vraeni sa lokalnog cache-a. Imajte
vidu da URLConnection sama po sebi ne odrava takav cache. Cache mora biti
obezbeen od eksternog programa kao to je pretraiva.

void setAllowUserInteraction(boolean allowUserInteraction)


boolean getAllowUserInteraction()

ako je allowUserInteraction taan, onda korisnik moe biti upitan za lozinke. Imajte u
vidu da URLConnection sama po sebi nema instalacije za izvravanje takvih pitanja.
Poziv mora izvriti eksterni program kao to je pretraiva ili plug-in pretraivaa.

void setConnectTimeout(int timeout) 5.0


int getConnectTimeout() 5.0

Setujte ili uzmite timeout za vezu (u milisekundama). Ako je timeout istekao pre nego
to je veza uspostavljena, read metod odgovarajueg ulaznog toka izbacuje
SocketTimeoutException.

void setReadTimeout(int timeout) 5.0


int getReadTimeout() 5.0

Setujte timeout za itanje podataka (u milisekundama). Ako je timeout istekao pre


nego to je operacija itanja bila uspena, connect metod izbacuje
SocketTimeoutException.

void setRequestProperty(String key, String value)

setuje zahtev polja zaglavlja.


MapString,ListString getRequestProperties() 1.4

vraa mapu zahtevanih opcija. Sve vrednosti za isti klju su poreane u listi.

void connect()

povezuje se na udaljeni izvor i vraa odgovor informacije zaglavlja.


MapString,ListString Map getHeaderFields() 1.4

vraa mapu odgovora zaglavlja. Sve vrednosti za isti klju su poreane u mapi.

String getHeaderFieldKey(int n)

uzima klju za n-ti odgovor polja zaglavlja, ili null ako je n0 ili vee od broja
odgovora polja zaglavlja.

String getHeaderField(int n)

uzima vrednost n-tog odgovora polja zaglavlja, ili null ako je n0 ili vee od broja
odgovora polja zaglavlja.

int getContentLength()

uzima duinu sadraja ako je dostupna ili 1 ako je nepoznata.

167

String getContentType

uzima tip sadraja, kao to je textplain ili imagegif.

String getContentEncoding()

uzima sadraj koda, kao to je gzip. Ova vrednost nije u uobiajenoj upotrebi, zato to
osnovni identitet koda ne treba da bude odreen sa Content-Encoding zaglavljem.

long getDate()
long getExpiration()
long getLastModified()

Uzmite datum kreiranja, isteka i poslednje promene izvora. Datumi su odreeni u


sekundama od ponoi, GMT, 1. Januar, 1970.

InputStream getInputStream()
OutputStream getOutStream()

Vratite tok za itanje sa izvora ili pisanje ka izvoru.

Object getContent()

bira odgovarajui sadrajni rukovodioc za itanje izvornih podataka i konvertovanje


istih u objekat. Ovaj metod nije koristan za itanje standardnih tipova kao to je
textplain ili imagegif ukoliko u suprotnom ne instalirate sopstveni sadrajni
rukovodioc.

Slanje oblika (formularnih) podataka


U prethodnom delu, videli ste kako se itaju podaci sa web servera. Sada emo vam
pokazati kako programi mogu biti poslati nazad na web server i programima koje web
server poziva.
Da bi se poslala informacija sa web itaa na web server, korisnik popunjava formular,
kao onaj na Slici 3-8.

168

Slika 3-8: HTML formular


Kada korisnik klikne Submit dugme (potvrdni taster), tekst u tekst poljima i settings
checkboxes i radio tasteri se alju nazad na web server. Web server poziva program koji
procesira ulaz korisnika.
Mnoge tehnologije omoguuju web serverima da pozivaju programe. Meu
najpoznatijima su Java servlets, JavaServer Faces, Microsoft ASP (Active Server Pages),
i CGI (Common Getaway Interface) skripte. Radi jednostavnosti, mi koristimo generiki
izraz skript za sporedni server program, bez obzira koja tehnologija se koristi.
Sporedni server skript procesira formularne podatke i proizvodi drugu HTML stranu koju
web server alje nazad pretraivau. Ovaj tok je ilustrovan na Slici 3-9. Strana odgovora
moe sadrati nove informacije (npr. u programu za traenje informacija). Web
pretraiva zatim prikazuje stranu odgovora.

169

Slika 3-9: Protok informacija tokom izvravanja sporednog server skripta


Ne diskutujemo implementaciju sporednih server skripti u ovoj knjizi. Na interes je
samo pisanje klijent programa koji sarauju sa sporednim server skriptima.
Kada su formularni podaci poslati na web server, nije vano da li servlet interpretira
podatke ili ih interpretira CGI skript ili neka druga sporedna tehnologija. Korisnik alje
podatke na web server u standardnom formatu i web server se brine o tome da se oni
proslede programu koji generie odgovor.
Dve komande, nazivaju se GET I POST, su esto koriene za slanje informacija na web
server.
U GET komandi jednostavno prikaite parametre na kraj URL-a. URL ima oblik
http://host/script?prameters

Npr. u vreme pisanja, Yahoo! web sajt ima skript, pymaps.py, na host-u
maps.yahoo.com. Skript zahteva dva parametra, addr i csz. Vi razdvajate parametre sa i
kodirate parametre, koristei sledeu shemu.
Zamenite sve blanko karaktere sa . Zamenite sve nealfanumerike karaktere sa ,
praene sa dvocifrenim heksadecimalnim brojem. Npr. da bi ste preveli ime ulice S.Main,
koristite S2eMain, poto je heksadecimalni broj 2e (ili decimalni 46 ) ASCII kod od
. karaktera. Ovaj kod spreava bilo koje meuprograme da petljaju sa belinama i
interpretiraju druge specijalne karaktere.
Ova kod shema se zove URL kodiranje.
Npr. da bi ste dobili mapu od 1 Infinite Loop, Cupertino, CA, jednostavno zahtevajte
sledei URL:
http://maps.yahoo.com/py/maps.py?addr=1+Infinite+Loop&csz=Cupertino+CA

GET komanda je jednostavna, ali ima veliko ogranienje koje je ini relativno
nepopularnom: mnogi pretraivai imaju ogranien broj karaktera koje moete ukljuiti u
GET zahtev.

170
U POST komandi, ne dodajete parametre na URL. Umesto toga dobijate izlazni tok od
URLConnection i piete namevalue parove na izlazni tok. I dalje morate da kodirate
URL vrednosti i razdvojite ih sa karakterima.
Pogledajmo ovaj proces detaljnije. Da bi ste poslali podatke skriptu, prvo uspostavite
URLConnection.
URL url = new URL(http://host/script);
URLConnection connection = url.openConnection();

Onda, pozovite setDoOutput metod da postavite vezu za izlaz.


connection.setDoOutput(true);

Dalje, pozovite getOutputStream da biste dobili tok kroz koji moete slati podatke
serveru. Ako aljete tekst serveru zgodno je da prebacite taj tok u PrintWriter.
PrintWriter out = new PrinterWriter(connection.getOutputStream());

Sada ste spremni za slanje podataka serveru:


out.print(name1 + ''='' + URLEncoder.encode(value1, ''UTF-8'') + ''&'');
out.print(name2 + ''='' + URLEncoder.encode(value2, ''UTF-8''));

Zatvorite izlazni tok.


out.close();

Konano, pozovite getInputStream i proitajte odgovor servera.


Proletimo kroz praktini primer.Web sajt http://www.census.gov/ipc/www/idb-print.html sadri
formular o podacima populacije (vidite Sliku 3-8 na str. 167). Ako pogledate html izvor
(source), videete sledei HTML tag:
<form method=post action=''/cgi-bin/ipc/idbsprd''>

Ovaj tag znai, da je ime skripta, izvrenog kada korisnik klikne potvrdno (Submit)
dugme /cgi-bin/ipc/idbsprd, i da morate koristiti POST komandu za slanje podataka
skriptu.
Dalje, morate da pronaete imena polja koja skript oekuje. Pogledajte korisnike
interface komponente. Svaka od njih ima a name atribut, npr.
<select name=''tbl'' size=8>
<option value=''001''>001 Total Midyear Population</option>
more options...
</select>

Ovo vam govori da je ime polja tbl. Ovo polje odreuje tip populacione table. Ako
odredite tip table 001, dobiete tablu cele populacije srednjeg doba. Ako pogledate dalje,
nai ete takoe polje sa imenom drave, cty sa vrednostima, kao to je US za United
States i CH (!) za Kinu. (naalost, Cenzus Biro izgleda nije svestan ISO-3166 standarda
za kodove zemalja.)
Konano, polje sa imenom optyr dozvoljava izbor intervala godina. Npr. samo emo ga
postaviti na poslednju proveru. Npr. da biste dobili poslednje podatke cele kineske
populacije srednjeg doba, konstruiite ovu nisku:
Tbl=1&cty=CH&optyr=latest+checked

Poaljite nisku URL-u


http://www.census.gov/cgi-bin/ipc/idbsprd:

Skript vraa sledei odgovor:


<PRE>
U.S. Bureau of the Census, International Data Base
Table 001. Total Midyear population
------------------- -----------------------Country of area/

171
Year
Population
------------------- -----------------------China
2004
1,298,847,624
------------------- -----------------------Source: U.S. Bureau of the Census, International
Data Base
</PRE>

Kao to moete videti, ovaj odreeni skript se ne bavi konstrukcijom lepih tabli. Zato
smo ga i uzeli za primer lako je videti ta se dogaa sa skriptom poto moe biti
zbunjujue protumaiti sloen set HTML tagova koje drugi skriptovi proizvode.
Program u Primeru 3-6 alje POST podatke Cenzus Birou. Mi omoguavamo da
jednostavan GUI izabere dravu i vidi izvetaj (pogledajte Sliku 3-10).

Slika 3-10: Skupljanje informacija sa servera


U doPost metodi, prvo otvaramo vezu, zovemo setDoOutput(true) i otvaramo izlazni tok.
Onda nabrajamo imena i vrednosti u Map objektu. Za svaki od njih aljemo ime, =
karakter, vrednost i & separator.
out.print(name);
out.print('=');
out.print(URLEncoder.encode(value, ''UTF-8'');
if (more pairs) out.print('&');

Konano itamo odgovor sa servera.


Postoji jedna potekoa sa itanjem odgovora. Ako se ikada desi greka u skriptu, onda
poziv na connection.getInputStream() izbacuje FileNotFoundException. tavie, server
jo uvek alje greku i vraa pretraiva na stranu iza (error page back), kao to je opte
prisutan Error 404 page not found. Da biste uhvatili ovu pogrenu stranu, izbacujete
URLConnection objekat u HttpURLConnection klasu i pozivate njen getErrorStream
metod:
InputStream err = ((HttpURLConnection) connection).getErrorStream());

172
Tehnika koju ovaj program prikazuje je korisna kad god imate potrebu da zatraite
informaciju sa postojeeg web sajta. Jednostavno potraite parametre koje treba poslati
(obino pregledom HTML izvora web strane koja prenosi isti zahtev) i onda uklonite
HTML tagove i druge nepotrebne informacije iz odgovora.
Primer 3-6: PostTest.java
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
Program demonstrira kako da koristimo URLConnection klasu za POST zahteve
*/
public class PostTest
{
public static void main(String[] args)
{
JFrame frame = new PostTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class PostTestFrame extends JFrame
{
/**
Pravi POST zahtev i vraca odgovor serveru
Parametar urlString je URL koji treba da post
Parametar nameValuePairs je mapa imena/vrednosti parova koji zadovoljava zahtev
Vraca odgovor servera (ili od ulaznog toka ili od izlaznog toka)
*/
public static String doPost(String urlString, Map<String, String> nameValuePairs)
throws IOException
{
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream());
boolean first = true;
for (Map.Entry<String, String> pair : nameValuePairs.entrySet())
{
if (first) first = false;
else out.print('&');
String name = pair.getKey();
String value = pair.getValue();
out.print(name);
out.print('=');
out.print(URLEncoder.encode(value, "UTF-8"));
}

173
out.close();
Scanner in;
StringBuilder response = new StringBuilder();
try
{
in = new Scanner(connection.getInputStream());
}
catch (IOException e)
{
if (!(connection instanceof HttpURLConnection)) throw e;
InputStream err
= ((HttpURLConnection)connection).getErrorStream();
if (err == null) throw e;
in = new Scanner(err);
}
while (in.hasNextLine())
{
response.append(in.nextLine());
response.append("\n");
}
in.close();
return response.toString();
}
public PostTestFrame()
{
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
setTitle("PostTest");
JPanel northPanel = new JPanel();
add(northPanel, BorderLayout.NORTH);
final JComboBox combo = new JComboBox();
for (int i = 0; i < countries.length; i += 2)
combo.addItem(countries[i]);
northPanel.add(combo);
final JTextArea result = new JTextArea();
add(new JScrollPane(result));
JButton getButton = new JButton("Get");
northPanel.add(getButton);
getButton.addActionListener(new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
new Thread(new
Runnable()
{
public void run()
{
final String SERVER_URL = "http://www.census.gov/cgi-bin/ipc/idbsprd";
result.setText("");
Map<String, String> post = new HashMap<String, String>();

174
post.put("tbl", "001");
post.put("cty", countries[2 * combo.getSelectedIndex() + 1]);
post.put("optyr", "latest checked");
try
{
result.setText(doPost(SERVER_URL, post));
}
catch (IOException e)
{
result.setText("" + e);
}
}
}).start();
}
});
}
private static String[] countries = {
"Afghanistan", "AF", "Albania", "AL", "Algeria", "AG", "American Samoa", "AQ",
"Andorra", "AN", "Angola", "AO", "Anguilla", "AV", "Antigua and Barbuda", "AC",
"Argentina", "AR", "Armenia", "AM", "Aruba", "AA", "Australia", "AS", "Austria", "AU",
"Azerbaijan", "AJ", "Bahamas, The", "BF", "Bahrain", "BA", "Bangladesh", "BG",
"Barbados", "BB", "Belarus", "BO", "Belgium", "BE", "Belize", "BH", "Benin", "BN",
"Bermuda", "BD", "Bhutan", "BT", "Bolivia", "BL", "Bosnia and Herzegovina", "BK",
"Botswana", "BC", "Brazil", "BR", "Brunei", "BX", "Bulgaria", "BU", "Burkina Faso", "UV",
"Burma", "BM", "Burundi", "BY", "Cambodia", "CB", "Cameroon", "CM", "Canada", "CA",
"Cape Verde", "CV", "Cayman Islands", "CJ", "Central African Republic", "CT", "Chad", "CD",
"Chile", "CI", "China", "CH", "Colombia", "CO", "Comoros", "CN", "Congo (Brazzaville", "CF",
"Congo (Kinshasa)", "CG", "Cook Islands", "CW", "Costa Rica", "CS", "Cote d'Ivoire", "IV",
"Croatia", "HR", "Cuba", "CU", "Cyprus", "CY", "Czech Republic", "EZ", "Denmark", "DA",
"Djibouti", "DJ", "Dominica", "DO", "Dominican Republic", "DR", "East Timor", "TT",
"Ecuador", "EC", "Egypt", "EG", "El Salvador", "ES", "Equatorial Guinea", "EK",
"Eritrea", "ER", "Estonia", "EN", "Ethiopia", "ET", "Faroe Islands", "FO", "Fiji", "FJ",
"Finland", "FI", "France", "FR", "French Guiana", "FG", "French Polynesia", "FP",
"Gabon", "GB", "Gambia, The", "GA", "Gaza Strip", "GZ", "Georgia", "GG", "Germany", "GM",
"Ghana", "GH", "Gibraltar", "GI", "Greece", "GR", "Greenland", "GL", "Grenada", "GJ",
"Guadeloupe", "GP", "Guam", "GQ", "Guatemala", "GT", "Guernsey", "GK", "Guinea", "GV",
"Guinea-Bissau", "PU", "Guyana", "GY", "Haiti", "HA", "Honduras", "HO",
"Hong Kong S.A.R", "HK", "Hungary", "HU", "Iceland", "IC", "India", "IN", "Indonesia", "ID",
"Iran", "IR", "Iraq", "IZ", "Ireland", "EI", "Israel", "IS", "Italy", "IT", "Jamaica", "JM",
"Japan", "JA", "Jersey", "JE", "Jordan", "JO", "Kazakhstan", "KZ", "Kenya", "KE",
"Kiribati", "KR", "Korea, North", "KN", "Korea, South", "KS", "Kuwait", "KU",
"Kyrgyzstan", "KG", "Laos", "LA", "Latvia", "LG", "Lebanon", "LE", "Lesotho", "LT",
"Liberia", "LI", "Libya", "LY", "Liechtenstein", "LS", "Lithuania", "LH", "Luxembourg", "LU",
"Macau S.A.R", "MC", "Macedonia, The Former Yugo. Rep. of", "MK", "Madagascar", "MA",
"Malawi", "MI", "Malaysia", "MY", "Maldives", "MV", "Mali", "ML", "Malta", "MT",
"Man, Isle of", "IM", "Marshall Islands", "RM", "Martinique", "MB", "Mauritania", "MR",
"Mauritius", "MP", "Mayotte", "MF", "Mexico", "MX", "Micronesia, Federated States of", "FM",
"Moldova", "MD", "Monaco", "MN", "Mongolia", "MG", "Montserrat", "MH", "Morocco", "MO",
"Mozambique", "MZ", "Namibia", "WA", "Nauru", "NR", "Nepal", "NP", "Netherlands", "NL",
"Netherlands Antilles", "NT", "New Caledonia", "NC", "New Zealand", "NZ", "Nicaragua", "NU",
"Niger", "NG", "Nigeria", "NI", "Northern Mariana Islands", "CQ", "Norway", "NO",
"Oman", "MU", "Pakistan", "PK", "Palau", "PS", "Panama", "PM", "Papua New Guinea", "PP",
"Paraguay", "PA", "Peru", "PE", "Philippines", "RP", "Poland", "PL", "Portugal", "PO",
"Puerto Rico", "RQ", "Qatar", "QA", "Reunion", "RE", "Romania", "RO", "Russia", "RS",
"Rwanda", "RW", "Saint Helena", "SH", "Saint Kitts and Nevis", "SC", "Saint Lucia", "ST",

175
"Saint Pierre and Miquelon", "SB", "Saint Vincent and the Grenadines", "VC", "Samoa", "WS",

"San Marino", "SM", "Sao Tome and Principe", "TP", "Saudi Arabia", "SA", "Senegal", "SG",
"Serbia and Montenegro", "YI", "Seychelles", "SE", "Sierra Leone", "SL", "Singapore", "SN",
"Slovakia", "LO", "Slovenia", "SI", "Solomon Islands", "BP", "Somalia", "SO",
"South Africa", "SF", "Spain", "SP", "Sri Lanka", "CE", "Sudan", "SU", "Suriname", "NS",
"Swaziland", "WZ", "Sweden", "SW", "Switzerland", "SZ", "Syria", "SY", "Taiwan", "TW",
"Tajikistan", "TI", "Tanzania", "TZ", "Thailand", "TH", "Togo", "TO", "Tonga", "TN",
"Trinidad and Tobago", "TD", "Tunisia", "TS", "Turkey", "TU", "Turkmenistan", "TX",
"Turks and Caicos Islands", "TK", "Tuvalu", "TV", "Uganda", "UG", "Ukraine", "UP",
"United Arab Emirates", "TC", "United Kingdom", "UK", "United States", "US", "Uruguay", "UY",
"Uzbekistan", "UZ", "Vanuatu", "NH", "Venezuela", "VE", "Vietnam", "VM",
"Virgin Islands", "VQ", "Virgin Islands, British", "VI", "Wallis and Futuna", "WF",
"West Bank", "WE", "Western Sahara", "WI", "Yemen", "YM", "Zambia", "ZA", "Zimbabwe", "ZI"
};
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 300;
}

Na primer program koristi URLConnection klasu da poalje podatke na web sajt. Vie
radoznalosti radi nego zbog praktine upotrebe, moda ete eleti da znate koju
informaciju URLConnection alje serveru kao dodatak podacima koje vi obezbeujete.
URLConnection objekat prvo alje zahtev zaglavlja serveru. Kada aljete formularne
podatke, zaglavlje mora ukljuiti:
Content-Type: application/x-www-form-urlencoded

Morate takoe odrediti duinu sadraja, npr.


Content-Lenght: 124

Kraj ovog zaglavlja je indukovan praznom linijom. Zatim, sledi odreena koliina
podataka. Web server skida zaglavlje i upuuje odreenu koliinu podataka na sporedni
server skript.
Primetite da URLConnection objekat baferuje sve podatke na izlazni tok poto prvo mora
utvrditi ukupnu duinu sadraja.
java.net.HttpURLConnection 1.0

InputStream getErrorStream()
vraa tok sa kojeg moete itati poruke o grekama web servera.
.java.net.URLEncoder 1.0

static String encode(String s, String encoding) 1.4

vraa URL kodirani oblik niske s, koristei datu shemu kodiranja karaktera.
(Preporuena shema je UTF-8) U URL kodu, karakteri A-Z, a-z, 0-9, -,

_, . i = ostaju nepromenjeni. Belina se kodira u - i svi ostali karakteri se

176
kodiraju u sled kodiranih bajtova, oblika %XY, gde je 0xXY heksadecimalna
vrednost bajta.
java.net.URLDecoder 1.2

static string decode(String s, String encoding) 1.4

vraa kod URL kodirane niske s po datoj shemi kodiranja karaktera.

Napredno socket programiranje


U sledeem odeljku, pokrivamo napredna pitanja koja se postavljaju u stvarnom svetu
programa. Prvo vam pokazujemo kako da koristite timeout-e i interrupts da bi se izborili
sa grekama veze. Pokazujemo vam kako half-close (poluzatvoreni) mehanizam moe
pojednostaviti zahtev protokola i zavravamo sa odeljkom o internet vezama.

Socket pauze
U stvarnosti, ne elite samo da itate sa socketa zato to e metode itanja biti blokirane
dok podaci ne budu dostupni. Ako je host nedostupan, onda vaa aplikacija eka dugo
vremena i vi ste na milosti pozadinskog operativnog sistema dok se ona ne obustavi
svremenom.
Umesto toga, trebalo bi da odluite koja timeout vrednost je razumna za vau odreenu
aplikaciju. Zatim, pozovite setSoTimeout metod da bi setovali timeout vrednost (u
milisekundama).
Socket s = new Socket(...);
s.setSoTimeout(10000); // pauza posle 10 sekundi

Ako je timeout vrednost bila setovana za socket, onda svi podsledovi koji itaju i piu
operacije izbacuju SocketTimeoutException kada se do timeout-a dolo pre nego to je
operacija zavrena. Moete uhvatiti taj izuzetak i reagovati na timeout.
Try
{
Scanner in = new Scanner(s.gerInputStream());
String line = in.nextLine();
...
}
catch(InteruptedIOException exception)
{
react to timeout
}

Postoji dodatan timeout kome morate da se obratite: Konstruktor


Socket (String host, int port)

moe blokirati beskonano dok inicijalna veza nije uspostavljena.


Po JDK 1.4, moete prevazii ovaj problem prvo konstrukcijom nepovezanog socketa, a
zatim povezivanjem njega sa timeout-om.
Socket s = new Socket();
s.connect(new InetSocketAddress(host, port), timeout);

Ometajui socket-i

177
Kada se poveete na socket, tekua nit je blokirana dok se veza ne uspostavi ili timeout
ne istekne. Slino, kada itate ili piete podatke kroz socket, tekua nit je blokirana dok
operacija nije uspena ili je istekla.
U interaktivnim aplikacijama eleete da date opciju korisnicima da jednostavno iskljue
socket vezu koja ne daje rezultete. tavie, ako je nit blokirana na socketu koji ne
odgovara, ne moete je odblokirati pozivanjem interrupt.
Da bi omeli socket operaciju, koristite SocketChannel, element java.nio paketa. Otvorite
SocketChannel ovako:
SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port);

Kanal nema povezanih tokova . Umesto toga, ima read i write metode koji ine Buffer
objekte korisnim. (Pogledajte Deo 1, poglavlje 12 za vie informacija o NIO baferima.)
Ove metode su deklarisane u interfejsima ReadableByteChannel i WrittableByteChannel.
Ako ne elite da se zanimate sa baferima, moete koristiti Scanner klasu za itanje sa
SocketChannel-a zato to Scanner ima konstruktor sa ReadableByteChannel-om:
Scanner in = new Scanner(channel);

Da bi ste uputili kanal na izlazni tok, koristite statiki Channels.newOutputStream metod.


OutputStream outStream = Channels.newOutputStream(channel);

To je sve to je potrebno da uradite. Kad god je nit ometena tokom otvaranja, itanja ili
pisanja operacije, operacija se ne blokira, ali se zavrava sa izuzetkom.
Program u Primeru 3-7 pokazuje kako nit koja ita sa servera moe biti ometena. Server
alje tok nasuminih brojeva korisniku. tavie, ako je Busy checkbox proveren, onda se
server pretvara da je zauzet i ne alje nita. U bilo kom sluaju, moete kliknuti Cancel
dugme i veza e se prekinuti (pogledajte Sliku 3-11).

Slika 3-11: Ometanje socketa


Primer 3-7: InterruptibleSocketTest.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.net.*;
import java.io.*;
import java.nio.channels.*;

178
import javax.swing.*;
/**
Ovaj program pokazuje kako se presrece socket kanal
*/
public class InterruptibleSocketTest
{
public static void main(String[] args)
{
JFrame frame = new InterruptibleSocketFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class InterruptibleSocketFrame extends JFrame
{
public InterruptibleSocketFrame()
{
setSize(WIDTH, HEIGHT);
setTitle("InterruptibleSocketTest");
JPanel northPanel = new JPanel();
add(northPanel, BorderLayout.NORTH);
messages = new JTextArea();
add(new JScrollPane(messages));
busyBox = new JCheckBox("Busy");
northPanel.add(busyBox);
startButton = new JButton("Start");
northPanel.add(startButton);
startButton.addActionListener(new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
startButton.setEnabled(false);
cancelButton.setEnabled(true);
connectThread = new Thread(new
Runnable()
{
public void run()
{
connect();
}
});
connectThread.start();
}
});
cancelButton = new JButton("Cancel");
cancelButton.setEnabled(false);
northPanel.add(cancelButton);
cancelButton.addActionListener(new

179
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
connectThread.interrupt();
startButton.setEnabled(true);
cancelButton.setEnabled(false);
}
});
server = new TestServer();
new Thread(server).start();
}
/**
Povezuje se na test server
*/
public void connect()
{
try
{
SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8189));
try
{
in = new Scanner(channel);
while (true)
{
if (in.hasNextLine())
{
String line = in.nextLine();
messages.append(line);
messages.append("\n");
}
else Thread.sleep(100);
}
}
finally
{
channel.close();
messages.append("Socket closed\n");
}
}
catch (IOException e)
{
messages.append("\nInterruptibleSocketTest.connect: " + e);
}
catch (InterruptedException e)
{
messages.append("\nInterruptibleSocketTest.connect: " + e);
}
}
/**
Visenitni server koji slusa port 8189 I salje nasumicne brojeve klijentu

*/
class TestServer implements Runnable
{

180
public void run()
{
try
{
int i = 1;
ServerSocket s = new ServerSocket(8189);
while (true)
{
Socket incoming = s.accept();
Runnable r = new RandomNumberHandler(incoming);
Thread t = new Thread(r);
t.start();
}
}
catch (IOException e)
{
messages.append("\nTestServer.run: " + e);
}
}
}
/**
Ova klasa barata klijentovim unosom za jednu server socket vezu
*/
class RandomNumberHandler implements Runnable
{
/**
konstruise baratac
parametar i je dolazeci socket

*/
public RandomNumberHandler(Socket i)
{
incoming = i;
}
public void run()
{
try
{
OutputStream outStream = incoming.getOutputStream();
PrintWriter out = new PrintWriter(outStream, true /* autoFlush */);
Random generator = new Random();
while (true)
{
if (!busyBox.isSelected()) out.println(generator.nextInt());
Thread.sleep(100);
}
}
catch (IOException e)
{
messages.append("\nRandomNumberHandler.run: " + e);
}
catch (InterruptedException e)
{
messages.append("\nRandomNumberHandler.run: " + e);

181
}
}
private Socket incoming;
}
private Scanner in;
private PrintWriter out;
private JButton startButton;
private JButton cancelButton;
private JCheckBox busyBox;
private JTextArea messages;
private TestServer server;
private Thread connectThread;
public static final int WIDTH = 300;
public static final int HEIGHT = 300;
}

Polu-Zatvorenost (Half-Close)
Kada korisniki program poalje zahtev serveru, server mora biti u mogunosti da utvrdi
kada dolazi do kraja zahteva.Iz tog razloga, mnogi Internet protokoli (kao to je SMTP)
su linijski orjentisani. Drugi protokoli sadre zaglavlje koje odreuje veliinu traenih
podataka. U suprotnom, pokazivanje kraja traenih podataka je tee nego pisanje
podataka fajlu. Kod fajla, vi biste ga samo zatvorili posle svih podataka. tavie, ako
zatvorite socket, onda odmah prekinite vezu sa serverom.
Half-Close prevazilazi ovaj problem. Moete zatvoriti izlazni tok socketa, ime
pokazujete serveru na kraj traenih podataka, ali ostavite ulazni tok otvoren, tako da
moete proitati odgovor.
Korisnika strana izgleda ovako:
Socket socket = new Socket(host, port);
Scanner in = new Scanner(socket.getInputStream());
PrintWriter writer = new PrintWriter(socket.getOutputStream());
// salje zahtevane podatke
writer.print(...);
writer.flush();
socket.shutdownOutput();
// sada je socket polu-zatvoren
// cita odgovor
while (in.hasNextLine()) != null ) { String line = in.nextLine(); ... }
socket.close();

Strana srvera jednostavno ita ulaz sve dok ne doe do kraja ulaznog toka.
Naravno, ovaj protokol je koristan samo za jednokratne (one-shot) servise, kao to je
HTTP gde se klijent povezuje, trai odgovor, uzima ga i zatim prekida vezu.
Internet Adrese
Obino, ne morate mnogo brinuti o internet adresama numerike host adrese koje se
sastoje od 4 bajta (ili sa IPv6, 16 bajtova), kao to je 132.163.4.102. tavie, moete
koristiti InetAddress klasu, ako treba konvertovati imena hostova i internet adrese.
Po JDK 1.4, java.net paket podrava IPv6 internet adrese, ukoliko ga podrava i host
operativni sistem.

182
Statini getByName metod vraa InetAddress objekt host-a. Npr.
InetAddress address = InetAddress.getByName(''time-A.timefreq.bldrdoc.gov'');

vraa InetAddress objekat koji skriva sled etiri bajta 132.163.4.104. Moete pristupiti
bajtovima metodom getAddress
byte[] addressBytes = address.getAddress();

Neka imena host-ova sa dosta prometa odgovaraju viestrukim internet adresama, da bi


se olakalo uitavanje. Npr. tokom pisanja toga, ime host-a java.sun.com odgovara trima
razliitim internet adresama. Jedna od njih je uzeta nasumice kada se host-u pristupi.
Moete dobiti sve host-ove sa getAllByName metodom.
InetAddress[] address = InetAddress.getAllByName(host);

Konano, nekada su vam potrebne adrese lokalnog host-a. Ako samo traite adresu
localhost-a, uvek dobijate adresu 127.0.0.1 koja nije veoma korisna. Umasto toga,
koristite sratini getLocalHost metod da dobijete adresu vaeg lokalnog host-a.
InetAddress address = InetAddress.getLocalHost();

Primer 3-8 je jednostavan program koji tampa internet adresu vaeg lokalnog host-a ako
ne odredite nijedan parametarkomandne linije, ili sve internet adrese drugog host-a ako
odredite ime host-a u komandnoj liniji, kao:
Java InetAddressTest java.sun.com

Primer 3-8: InetAddressTest.java


import java.net.*;
/**
Ovaj program demonostrira InetAddress klasu.
Dopisite ime host-a kao argument komandne linije, ili pokrenite
bez argumenata komndne linije da vidite adresu
lokalnog host-a
*/
public class InetAddressTest
{
public static void main(String[] args)
{
try
{
if (args.length > 0)
{
String host = args[0];
InetAddress[] addresses = InetAddress.getAllByName(host);
for (InetAddress a : addresses)
System.out.println(a);
}
else
{
InetAddress localHostAddress = InetAddress.getLocalHost();
System.out.println(localHostAddress);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

183
NAPOMENA: Ova kniga, pokriva samo TCP (Transmission Control Protocol)
mreni protokol. TCP uspostavlja pouzdanu vezu izmeu dva raunara.
Java platforma takoe podrava tzv. UDP (User Datagram Protocol)
protokol, koji moe da se koristi za slanje paketa (tzv. datagrama) koji je
mnogo manje povrinski nego TCP. Nedostatak je to paketi mogu da
budu isporueni u nasuminom poretku ili ak svi odjednom. Sve je na
primaocu da stavi pakete u poredak i da zatrai ponovno slanje paketa koji
nedostaju. UDP je najprikladniji za aplikacije u kojima paketi koji nedostaju
mogu da se toleriu, na primer, u audio ili video tokovima, ili stalnim
izraunavanjima.

java.net.Socket 1.0

Socket()

kreira socket koji jo nije bio povezan.

void connect(SocketAddress address) 1.4

void connect(SocketAddress address, int timeoutInMilliseconds) 1.4

povezuje ovaj socket na datu adresu.


povezuje ovaj socket na datu adresu ili se vraa ako je isteklo vreme intervala.

boolean isConnected() 1.4

vraa true (tano), ako je socket povezan.

boolean isClosed() 1.4

vraa true (tano), ako je socket zatvoren.

void setSoTimeout(int timeoutInMilliseconds) 1.1

setuje vreme za blokiranje, za itanje odgovora na ovaj socket. Ako je timeout


postignut, onda se InterruptedIOException javlja.

void shutdownOutput() 1.3

setuje izlazni tok na kraj toka.

void shutdownInput() 1.3

setuje ulazni tok na kraj toka.

bollean isOutputShutdown() 1.4

vraa true ako je izlaz bio ugaen.

bollean isInputShutdown() 1.4

vraa true ako je ulaz bio ugaen.


java.net.InetAddress 1.0

static InetAddress getByName(String host)


static InetAddress[] getAllByName(String host)

184
konstruie InetAddress ili niz svih internet adresa za dato ime host-a.

staticInetAddress getLocalHost()

konstruie InetAddress za lokalni host.

byte[] getAddress()

vraa niz bajtova koji sadri numeriku adresu.

String getHostAddress()

vraa nisku sa decimalnim brojevima odvojenu periodima, npr. 132.163.4.102.

String getHostName()

vraa ime host-a.

java.net.InetSocketAddress 1.4

InetSocketAddress(String hostname, int port)

konstruie objekat adrese sa datim host-om i port-om, reavajui ime hosta u toku
konstrukcije. Ako ime hosta ne moe biti reeno, onda e opcija adrese objekta
unresolved biti setovana na true (tano).

boolean isUnresolved()

vraa true ako ovaj adresa objekat ne moe biti reen.


java.nio.channels.SocketChannel 1.4

static SocketChannel open(SocketAddress address)

otvara socket kanal i povezuje ga na udaljenu adresu.


java.nio.channels.Channels 1.4

static InputStream newInputStream(ReadableByteChannel channel)

konstruie ulazni tok koji ita sa datog kanala.

static OutputStream newOutputStream(WrittableByteChannel channel)

konstruie izlazni tok koji pie na datom kanalu.

185

You might also like