Síťové API Javy - balík java.net
Služby pro síťovou komunikaci jsou součástí Javy od jejich prvních verzí.
Třídy pro tvorbu síťových aplikací jsou umístěny v balíku java.net. V současné době
je podporována komunikace v prostředí intranet/internet na bázi rodiny protokolů TCP/IP.
Mimo prostředků na spojově orientovanou a datagramovou komunikaci poskytuje balík možnosti
komunikace typu multicast, včetně metod pro připojování a odpojování se k jednotlivým multicast skupinám.
Kromě nízkoúrovňové komunikace založené na obvyklém API používajícím socketů je k dispozici řada
služeb zpřístupňující obsah síťových zdrojů na základě jejich identifikace pomocí URL (Uniform Resource Locator).
Mechanismus získávání obsahu z jednotlivých typů URL je uživatelsky modifikovatelný, lze doprogramovat
ovladače pro přístup k libovolné službě a pro zpracování libovolného typu obsahu (contents type).
Aplikace mohou být snadno modifikovány pro provoz ve speciálních síťových podmínkách (přítomnost firewallů,
proxy serverů, překlad adres) díky možnosti zaregistrování vlastní implementace soketů (zvlášť
pro sockety použité pro příjem spojení (server) a pro sockety využívané v prostředí klienta). Tím je možné vytvořit
transparentní mezivrstvu, provádějící příslušné překlady adres pro dané prostředí, poskytující např. autentikační informace
(třeba pro SOCKS server) nebo realizující šifrování či překódovávání přenášených dat.
URL: Uniform Resource Locator
- reprezentuje "ukazatel" na konkrétní zdroj na síti
- formát: služba://uživatel:heslo@host:port/cesta#reference
Reference není ve skutečnosti součástí URL, interpretuje ji klient jako část dokumentu, o kterou má uživatel zájem.
Interpretace je závislá na typu dokumentu
- data odkazovaného zdroje mohou být statická (v souboru) nebo generována dynamicky, tj. programem
(CGI, servlet, JSP, ...)
URL mohou být zadány absolutně nebo relativně vzhledem k síťovému zdroji, ve kterém se vyskytují.
Třídy a rozhraní balíku java.net
URL
- reprezentuje URL požadovaného síťového zdroje
- metody pro zjišťování jednotlivých částí URL:
getFile(), getHost(), getPort(), getProtocol() , getRef()
- metoda getContent() pro získání obsahu zdroje ve formě objektu poskytnutného příslušným ovladačem obsahu
(ekvivalent openConnection().getContent())
- metoda openStream() pro zpřístupnění obsahu daného zdroje ve formě datového proudu (ekvivalent openConnection().getInputStream())
- metoda openConnection() vrátí objekt URLConnection reprezentující spojení na zdroj odkazovaný tímto URL
- třídní metoda setURLStreamHandlerFactory() pro nastavení ovladače pro uživatelsky definované
služby použitelné v nových instancích URL
Při vytváření první instance URL pro daný protokol se vytvoří instance ovladače (třídy URLStreamHandler)
pro tento protokol.
Byla-li předem nastavena instance URLStreamHandlerFactory, získá se instance ovladače pro daný protokol
voláním metody createURLStreamHandler(protokol) nad instancí stream handler factory.
Jinak systém ovladač vytváří jako instanci třídy s názvem
< package > .< protoco > .Handler , kterou hledá
v některém z balíků specifikovaných systémovou vlastností java.protocol.handler.pkgs .
Pokud se vhodná třída nenajde, zkouší se v balíku sun.net.www.protocol.< protocol >.Handler , při selhání se vyhodí
výjimka MalformedURLException.
Poznámka: Patřičnou instanci URLStreamHandler lze také explicitně zadat při vytváření URL
(pokud to security manager dovolí)
Poznámka: URLStreamHandler může modifikovat části URL prostřednictvím (protected) metody
URL.set(String protocol, String host, int port, String file, String ref).
URLConnection
- (abstraktní) nadtřída všech tříd reprezentující komunikační spojení mezi aplikací a zdrojem
- získá se voláním openConnection() nad instancí příslušného URL (konstruktor je protected).
Ve skutečnosti se vrací instance podtřídy specializované na příslušný protokol
(např. HttpURLConnection , JarURLConnection)
- použití ke čtení a zápisu z/do přirazeného zdroje
- skutečné spojení se zdrojem se zřídí při volání connect(). Zde se také zjišťují informace o zdroji (hlavička, typ obsahu).
Spojení zůstane navázáno, informace o zdroji a jeho obsah jsou přístupné pomocí metod
- getContent()
- getHeaderField()
- getInputStream()
- getOutputStream()
Uvedené operace volají connect() implicitně, pokud v době jejich použití ještě nebylo spojení otevřeno.
- Před voláním connect() je možné nastavovat parametry zřizovaného spojení:
- setAllowUserInteraction() - dovolí/zakáže interakci systému s uživatelem. Interakce může být potřebná během
vytváření spojení (např. otevírání autentizačního dialogu)
- setUseCaches() - dovolí/zakáže použití dokumentu z WWW cache
- setIfModifiedSince() - dovolí načíst dokument pouze byl-li v poslední (nastavitelné) době modifikován
Existují také odpovídající get...() metody pro zjištění nastavených hodnot parametrů pro zřizování spojení.
Implicitní parametry pro všechny dále vytvářené instance URLConnection lze nastavit voláním třídních
metod setDefaultAllowUserInteraction() a setDefaultUseCaches().
- Parametry požadavku na zdroj jsou závislé na konkrétním protokolu a mohou být modifikovány metodou
setRequestProperty() a přednastaveny implicitně pro všechny nově vznikající instance URLConnection
metodou setDefaultRequestProperty().
Příklad: nastavení parametru "Accept-Language" pro požadavek HTTP
- Možnost enumerovat všechny klíče obsažené v hlavičce zdroje pomocí metody getHeaderFieldKey(index)
a získat jejich hodnoty metodou getHeaderField().
Pro přístup k nejčastěji používaným polím hlavičky jsou k dispozici metody
- getContentEncoding()
- getContentLength()
- getContentType()
- getDate()
- getExpiration()
- getLastModifed()
- metoda getContent() k získání obsahu daného zdroje.
Pomocí getContentType() se zjistí typ dokumentu, podle něj se nalezne odpovídající
instance ovladače obsahu, jeho prostřednictvím se provede načtení.
Poznámka: Pokud implementujeme novou podtřídu URLConnection, obvykle se redefinuje
metoda getContentsType().
- možnost nastavení contents handler factory (setContentHandlerFactory()) pro aplikaci.
Jejím prostřednictvím se budou dále vytvářet ovladače obsahů pro jednotlivé MIME typy.
- Podpora pro "odhadnutí" typu zdroje z jeho jména (guessContentTypeFromName())
nebo začátku obsahu (guessContentTypeFromStream() ) - na základě objektu registrovaného
s rozhraním FileNameMap, ten lze přeregistrovat (setFileNameMap() )
- Podpora pro přiřazení objektu požadovaných práv objektu spojení
Podtřídy třídy URLConnection, které jsou součástí JDK
HttpURLConnection
- specializace URLConnection pro podporu protokolu HTTP
- možnost automatické obsluhy přesměrování, pokud server oznámí přesunutí obsahu a doporučí nové URL
- možnost nastavení metody použité pro požadavek (GET, PUT, POST, HEAD, OPTIONS, DELETE, TRACE)
- možnost zjištění kódu odpovědi a (volitelného) doprovodného textu z odpovědi serveru na požadavek URL.
Třída definuje symbolické konstanty pro standardní kódy odpovědí z hlavičky odpovědi HTTP.
- zjištění, zda odpověď přišla z proxy
- v případě chyby možnost přečíst doprovodná data vrácená serverem
- možnost explicitního ukončení spojení
JarURLConnection
- specializace URLConnection pro podporu přímého přístupu do zdrojů, které jsou JAR soubory (Java archivy)
- syntaxe JAR URL: jar:< url > !/{entry}
JAR URL může reprezentovat JAR soubor jako celek, adresář v JAR souboru nebo položku v JAR souboru
- možnost zjištění manifestu JAR souboru
- možnost přečtení zadané položky JAR souboru
- možnost zjištění atributů
- zjištění certifikátu příslušné položky JAR souboru
Vazba ovladačů služeb (stream handlers) a ovladačů obsahu (content handlers) na systém
Aktivní URLStreamHandler umí otevřít spojení pro příslušný protokol a vrátit instanci odpovídající
podtřídy URLConnection pro tento protokol (metoda URLConnection openConnection(URL u)).
Aktivní URLStreamHandlerFactory vrací instanci URLStreamHandler na základě protokolu.
ContentHandlerFactory vrací instanci ContentHandler na základě MIME typu.
ContentHandler má jedinou metodu Object getContent(URLConnection urlc)
InetAddress
- reprezentuje IP (Internet Protocol) adresu
- možnost získávání IP adresy na základě doménového jména
- možnost zjišťování doménového jména na základě IP adresy
- testování, zda jde o multicast adresu
Socket
- reprezentuje socket pro spojově orientovanou komunikaci na klientské straně
- skutečnou implementaci poskytují instance podtříd třídy SocketImpl (i pro serverové sockety).
Základní implementaci v JDK poskytuje třída PlainSocketImpl
- aplikace může zajistit vytváření instancí socketů se zvláštním chováním nastavením "socket factory",
která skutečné implementace poskytuje => užitečné zejména v prostředí firewallů, proxy serverů,
překladu adres, ...
class Socket {
Socket(InetAddress address, int port);
Socket(String host, int port, InetAddress localAddr, int localPort);
/* konstruktory prověřují právo vytvořit socket u security manageru *./
getInetAddress();
getPort();
/* vrátí adresu, resp. port protistanice, na kterou je socket připojen */
getLocalAddress();
getLocalPort();
/* vrátí lokálně použitou adresu, resp. port */
getInputStream();
getOutputStream();
/* vrátí vstupní, resp. výstupní stream použitelný pro čtení, resp. zápis
dat na socketu */
setTcpNoDelay();
/* zákaz/povolení Nagleho algoritmu (s vysláním TCP segmentu se čeká
na příchod prahového množství dat) */
setSoLinger();
/* nastavení maximální doby čekání na odeslání zbývajících dat
při ukončování spojení */
setSoTimeout();
/* nastavení časového limitu pro blokující operaci čtení */
close();
/* rozpojení spojení a uzavření socketu */
setSocketImplFactory()
/* nastavení socket factory pro klientské sockety
(pokud to security manager dovolí) */
}
ServerSocket
- reprezentuje socket pro spojově orientovanou komunikaci na straně serveru
class ServerSocket {
ServerSocket(int port, int backlog, InetAddress bindAddr)
/* při konstrukci se dotazuje security manager, zda je poslouchání
na daném portu povoleno */
Socket accept();
/* čeká na spojení a po jeho navázání vrátí nový socket reprezentující
nové spojení. Při akceptování nového spojení je vyvolán security
manager s adresou a číslem portu klienta, ten musí spojení dovolit */
getInetAddress();
getLocalAddress()
/* vrátí (lokální) adresu a port, na které se čeká na požadavky spojení */
setSoTimeout()
/* nastavení časového limitu pro čekání na spojení accept() */
implAccept(socket)
/* pomocná metoda pro redefinici accept() v podtřídách, aby se vracela
vhodná podtřída Socket */
close();
/* rozpojení spojení a uzavření socketu */
static setSocketImplFactory()
/* nastavení socket factory pro serverové sockety (pokud to
security manager dovolí) */
}
DatagramSocket
- socket pro datagramovou komunikaci
- umožňuje i všesměrové (broadcast) vysílání
class DatagramSocket {
DatagramSocket(int port, InetAddress laddr);
/* security manager musí komunikaci na daném portu povolit */
getInetAddress(),
getPort();
/* zjištění adresy protistanice, na kterou budou datagramy z tohoto
socketu vysílány (pokud byl dříve s protistanicí socket svázán
metodou connect()) */
getLocalAddress();
getLocalPort();
/* vrací lokální adresu, resp. port přiřazený socketu */
setSoTimeout();
/* nastavení časového limitu pro blokující čekání na datagram
metodou receive() */
connect(InetAddress address, int port);
/* sváže socket s adresou protistanice, která se dále bude výhradně
užívat. Zde se prověřují práva na komunikaci se zadanou protistanicí
u security managera, při dalších operacích send() a receive() však již
prověřována nebudou */
disconnect();
/* odváže socket od protistanice */
send(DatagramPacket p);
/* zaslání datagramu (paketu) na zadanou stanici. Součástí instance
DatagramPacket jsou jak uživatelská data, tak adresa a port
protistanice. Pokud není socket svázán s adresou protistanice metodou
connect(), ověřuje se, je-li spojení mezi lokální adresou a adresou
a portem protistanice povoleno */
void receive(DatagramPacket p);
/* čeká na příchod datagramu. Data i identifikaci odesílatele uloží
do zadané instance DatagramPacket. Pokud je délka příchozího datagramu
větší než velikost předaného bufferu pro paket, je zpráva oříznuta.
Security manager ověřuje právo přijetí datagramu ze zadané adresy
(stejné jako pro accept u serverového socketu) */
close();
/* uzavření socketu */}
}
DatagramSocketImpl
Abstraktni bázová třída pro skutečné implementace datagramových a multicast socketů.
Základní implementaci v JDK poskytuje interní třída PlainDatagramSocketImpl.
MulticastSocket
- socket pro zasílání a příjem multicast UDP zpráv, dědí z DatagramSocket
- metody pro připojování ( joinGroup() ) a odpojování (leaveGroup() ) z multicast skupiny
- pro multicast vyhrazeny adresy třídy D v rozsahu 224.0.0.1 - 239.255.255.255
- nutné zapnutí podpory pro multicast v jádře systému (+ příp. návaznost na protokol IGMP)
Poznámky.
- socket nemusí být členem dané multicast skupiny, aby na ní mohl poslat datagram.
- více instancí multicast socketů se může připojit do mutlicast skupiny a na stejný port,
veškeré příchozí zprávy na tuto multicast skupinu a daný port obdrží všechny instance
- v současné verzi nesmějí mutlicast socketů využívat applety
class MulticastSocket : DatagramSocket {
MulticastSocket(int port);
setTimeToLive(); /* nastavení maximálního počtu přeskoků */
/* vysílaného multicast datagramu v síti */
joinGroup(); /* připojení do multicastové skupiny */
leaveGroup(); /* odpojení z multicastové skupiny */
}
DatagramPacket
- reprezentuje datagram vysílaný/přijímaný přes DatagramSocket nebo MulticastSocket
- konstrukce ze zadané adresy a portu příjemce a bufferu s daty nebo prázdného bufferu na příchozí data
- metody pro zjištění adresy a portu na kterou se datagram bude posílat nebo ze které přišel a jejich nastavení
- přečtení dat z datagramu a jejich délky, nastavení těchto dat
URLEncoder, URLDecoder
Pomocné třídy s metodami pro převod řetězce na MIME formát "x-www-form-urlencoded"a zpět.
Tento formát slouží pro předávání parametrů obsahujících nepísmenné znaky jako součást URL
(např. předávání parametrů z formulářů metodou GET).
URLClassLoader
Zavaděč tříd schopný číst třídy specifikované sadou URL odkazujících se na adresáře
na síti nebo JAR soubory
Podpora autentizace pro síťová spojení
Mechanismus pro poskytování autentizačních informací (mohou být pořadovány např. WWW serverem,
firewallem, SOCKS serverem, ...)
Authenticator
- abstraktní třída, instance podtříd reprezentuje objekt, který ví, jak získat příslušná autentizační data
(obvykle dotazem na uživatele).
- takovýto objekt se zaregistruje u systému třídní metodou Authenticator.setDefault()
- systém zaregistrovaný autentikátor dynamicky volá v okamžiku potřeby autentikace
(metoda getPasswordAuthentication()).
- instance autentikátoru může zjistit dodatečné informace o spojení požadujícím autentikaci (adresu a port serveru,
použitý protokol, prompt požadavku na autentikaci):
- getRequestingSite()
- get RequestingPort()
- getRequestingProtocol()
- getRequestingPrompt()
Na základě zjištěných údajů pak může poskytnout požadované autentizační informace
(ve formě objektu PasswordAuthentication)
PasswordAuthentication
Nosič dvojice < uživatelské_jméno, heslo > používaný instancí třídy Authenticator.