4. blok
Java síťová
Studijní cíl V tomto bloku studenti získají základní dovednosti při práci s Javou v síťovém prostředí. V úvodu budou zkoumány třídy pro práci se síťovými adresami InetAddress, InetSocketAddress a URL z balíčku java.net. Dále se budeme zabývat tzv. „socketovou“ komunikací (třídy Socket a ServerSocket) a v závěru se zaměříme na programování vícevláknových síťových aplikací pro více uživatelů-klientů, a jak použít moderní NIO (New I/O) rozhraní.
Doba nutná k nastudování
2 – 3 hodiny
4.1 Základy síťové komunikace Se vznikem internetu se můžeme na síťovou komunikaci v Javě (komunikace mezi více JVM) dívat dvěma pohledy-způsoby: 1. High Level • webové aplikace – Java Aplety, JSP, Servlety, EJB, JSF, Spring • distribuované systémy - RMI, Corba atd. 2. Low Level • komunikace na vrstvách internetového modelu TCP/IP (pomocí datagramů a socketů) • programátor je zodpovědný za celou komunikaci mezi klientem a serverem • i v tomto případě se jedná o distribuované aplikace 4.1.1 Model TCP/IP Javovské programy pracující na aplikační vrstvě využívají třídy z balíčků java.net, a java.nio:
1
4.2 Vybrané třídy z balíčku java.net (síťové API Javy) 4.2.1 java.net.InetAddress Tato třída reprezentuje adresu v síti dle IP protokolu a podporuje verze IP4 (32 bitů) i IP6 (128 bitů) pomocí svých potomků (Inet4Address a Inet6Address). Důležité (statické) metody: • • •
getByAddress(byte[] addr) – vrací adresu na základě pole bajtů (4 B pro IPv4, 16 B pro IPv6) getByName(String host) – vrací adresu podle jména hostitele getLocalHost() – vrací adresu pro localhost (klienta)
Ukázka části kódu:
4.2.2 java.net.InetSocketAddress Jedná se o kombinaci třídy InetAddress (předek) a čísla portu. Třída se využívá pro úplnou specifikaci adresy a k připojení soketů na server. Nejčastěji volané konstruktory: • •
InetSocketAddress(InetAddress addr, int port) InetSocketAddress(String hostName, int port)
Číslování portů umožňuje v informatice u protokolů TCP a UDP používat tzv. síťové porty, které pomocí speciálního čísla rozlišují v rámci jednoho počítače (resp. jedné IP adresy) různé běžící programy (služby). Rozsah portů: 0 – 1023:
rezervované porty („well know ports“) [20,21-ftp; 23-Telnet; 25-SMTP; 80-http; 443-HTTPS; …]
1024 – 49151:
registrované porty (použití portů by se mělo zaregistrovat u ICANN) [1521-Oracle Listener; 3306-mySQL; 27015-HalfLife; …]
49152 – 65535:
dynamicky přidělované a soukromé porty (ty můžeme využít)
2
Poznámka ICANN (vyslovováno anglicky „aj ken“) je zkratka pro Internet Corporation for Assigned Names and Numbers. Sídlo je v Marina Del Rey v Kalifornii. Jedná se o neziskovou organizaci, která byla založena roku 1998 proto, aby dohlížela na veškeré věci související s internetem, které dříve spravovaly jiné organizace. 4.2.3 Souhrn všech důležitých tříd z balíčku java.net Třídy pro adresaci: • •
InetAddress, InetSocketAddress (viz dříve) URL (i pro TCP komunikaci)
Třídy pro UDP komunikaci: •
DatagramPacket, DatagramSocket
Třídy pro TCP komunikaci: •
ServerSocket, Socket, URLConnection
Třídy výjimek: •
UnknownHostException, UnknownServiceException, MalformedURLException, ProtocolException, SocketException, PortUnreachableException, ConnectException
4.3 UDP komunikace Jedná se o tzv. datagramovou komunikaci pomocí např. protokolu UDP, kde komunikace probíhá pomocí balíků dat (datagramů). Komunikace je nespolehlivá, ale rychlá. V praxi se datagramová komunikace používá např. pro službu doménových jmen (DNS), některé způsoby multimediálních přenosů nebo také při vzdáleném volání procedur (RPC, RMI).
Poznámka UDP protokol (User Datagram Protocol) je jedním ze sady (nespojových) protokolů internetu. O protokolu UDP se říká, že nedává záruky na datagramy, které přenáší mezi počítači v síti. Někdy je označován jako nespolehlivý, ale to je velmi zavádějící označení. Na rozdíl od protokolu TCP totiž nezaručuje, zda se přenášený datagram neztratí, zda se nezmění pořadí doručených datagramů nebo zda se některý datagram nedoručí vícekrát.
3
4.4 TCP socketová komunikace Protokol TCP (Transmission Control Protocol) zaručuje, že všechna data dojdou od odesílatele k adresátovi beze změn, protože umožňuje opakovat přenos při ztrátě dat. Jedná se o tzv. přenos se stálým spojením pomocí socketů.
Přenos se stálým spojením Kroky spojení (zjednodušeně): 1. Server nastaví číslo portu, na kterém bude poslouchat a čeká na požadavky. 2. Klient se pokouší o spojení na dané adrese a daném čísle portu. 3. Pokud bylo spojení úspěšně navázáno, komunikace dále probíhá pomocí proudů Inputstream a OutputStream. Socketovou - spojovou komunikaci používá většina aplikací, např. HTTP, FTP, poštovní protokoly (SMTP, POP3, IMAP4), telnet, SSH atd. So(c)kety jsou základem téměř všech síťových protokolů včetně „javovských“ technologií, např. JDBC, EJB, RMI a CORBA. 4.4.1 java.net.ServerSocket Tato třída představuje jeden konec spojení - server, který naslouchá na přiděleném portu (ServerSocket(int port) - nejpoužívanější konstruktor). Pro připojení klienta je třeba dále vytvořit objekt třídy Socket. Nutné metody: •
accept() – blokování/čekání
4
•
close() – uzavření objektů
4.4.2 java.net.Socket Třída vytváří sokety, jak na straně serveru, tak i na straně klienta pro vytvoření a navázání spojení.
Spojení aplikací pomocí proudů propojených sokety Nejpoužívanější konstruktory: • •
Socket(String host, int port) Socket(InetAddress addr, int port)
Důležité metody: • • •
getInputStream() – získání vstupního proudu getOutputStream() – získání výstupního proudu close() – uzavření objektů
4.4.3 java.net.URL a java.net.URLConnection • URL (Uniform Resource Locator) – třída představuje tzv. ukazatel na konkrétní zdroj v síti; poskytuje služby zpřístupňující obsah síťových zdrojů o getProtocol(),getHost(),getPort(),… - získání částí URL o openConnection() - vrací objekt, který představuje spojení s jiným vzdáleným objektem o openStream() - vrací proud pro čtení vzdáleného objektu • URLConnection – umožní skutečné připojení do sítě k definovanému zdroji o getXxx() – informace o již připojeném zdroji o getInput[Output]Stream() - získání vstupního/výstupního proudu
5
Ukázka úplného kódu – TCP soketová komunikace [1 Server – 1 Client]:
Server
Client
4.5 TCP/IP – zpracování více klientů (multithreading) Aby server mohl zpracovávat více klientů, je třeba vyřešit dva hlavní problémy: 1. problém: řešení: 2. problém: řešení:
obsluha více než jednoho klienta nekonečná „čekací“ smyčka na serveru souběžné obsloužení více klientů pro každého klienta bude na serveru (ve smyčce) vytvořeno samostatné vlákno
I výše popsaná řešení mají své nevýhody: •
metoda accept() není synchronizovaná; problém u sdílených dat
6
•
zvyšující se počet klientů–vláken snižuje výkon aplikace
Konečné řešení (příklady na cvičení): • •
metodu accept() je třeba synchronizovat, např. pomocí synchronized bloku je možné využít nových nástrojů z balíčku java.nio (viz dále)
4.6 Knihovna java.nio Knihovna NIO (New I/O) přináší nové přístupy – třídy a metody pro práci se soubory, ale i se síťovými prostředky (sokety) bez nutnosti tvorby vláken. Knihovna se skládá ze tří hlavních balíčků: • •
- pro práci s tzv. buffery (existují pro všechny primitivní typy); buffery jsou výkonnější a nahrazují streamy java.nio.channels - pro práci se síťovými kanály a selektory
•
java.nio.charset
java.nio
- API pro práci se znakovými sadami
4.6.1 Buffery Dosud jsme si při přenášení dat z/do soketu vystačili s vyrovnávací pamětí, která byla implementovaná polem bajtů. NIO však přichází s rychlejším řešením, než jsou klasická pole. Pro každý primitivní datový typ (kromě boolean) nabízí tzv. třídy bufferů. Ty umožňují navíc takové operace, jakými jsou například přetáčení, nastavení značky atd. Navíc bajtový buffer lze alokovat jako nativní (direct) datovou strukturu. Třídy bufferů: •
ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
Každý buffer má čtyři důležité hodnoty: kapacitu, pozici, limit a značku a platí: 0 <= mark <= position <= limit <= capacity Důležité metody: • •
capacity(), limit(), position(), mark() put[Xxx](), get[Xxx]() rewind() přetočí buffer (vynuluje pozici a zruší značku); možnost znovu číst původní data
7
•
clear()
•
flip()
připraví buffer k novému použití (vynuluje pozici a nastaví limit na kapacitu) nastaví limit na aktuální pozici a tu vynuluje; práce pouze s definovanou částí bufferu
Poznámky ByteBuffer je nejvíce používaný pro práci se soubory a sokety (pro sokety je nejvhodnější tzv. přímý ByteBuffer – je nativní, tedy rychlý). Příklad vytvoření direct bufferu: ByteBuffer dBuffer = ByteBuffer.allocateDirect(256); Kapacita čili velikost vyrovnávací paměti je konstantní hodnota, kterou jsme zadali jako parametr metody allocate() nebo allocateDirect(). Zjistíme ji metodou capacity(). Limit je značka určená pro čtení a zápis do bufferu. Označuje index prvního prvku, který už nelze přečíst, nebo pozici, na kterou již nelze zapisovat (místo není volné). Aktuální limit vrací metoda limit(); změníme ho pomocí stejnojmenné metody s jedním celočíselným parametrem – limit(int novyLimit). Pozice určuje index aktuálního elementu, na kterém bude probíhat čtení nebo zápis. Zjišťuje a nastavuje se obdobně jako limit, tentokrát však přetíženou metodou position(). Značka je index prvku, který si můžeme označit metodou mark() a vrátit se na jeho pozici voláním metody reset(). 4.6.2 Síťové kanály (channels) Síťové kanály (balíček java.nio.channels) představují různé komunikační prostředky, jako jsou např. soubory, roury (pipes) a pro nás důležité síťové sokety. Balíček obsahuje tři třídy (kanály) pro práci se sítí: • •
DatagramChannel - pro UDP komunikaci ServerSocketChannel a SocketChannel – pro TCP komunikaci
Hlavní metody: •
read(), write(), accept()
Výše uvedené třídy jsou odvozeny od mnoha rozhraní nebo abstraktních tříd, např. od rozhraní Channel (s metodami isOpen() a close()) nebo od abstraktní třídy SelectableChannel poskytující pokročilé metody jako např.
8
register() pro zaregistrování selektoru nebo configureBlocking() pro nastavení kanálu do neblokujícího režimu. 4.6.3 Selektory Selektor je množina několika kanálů, u které můžeme sledovat, který z kanálůsoketů je aktivní (u aplikací s více klienty). Kanály-sokety „zabalené“ do selektoru (pomocí tzv. klíčů) tím odstraňují nutnost vytvářet pro každý soket nové vlákno. Aplikace pak obsahuje pouze jedno vlákno a vybírají se vždy kanály, do kterých přišla data – mluvíme o tzv. multiplexování. Ukázka části kódu pro vytvoření selektoru a zaregistrování kanálů:
4.7 RMI (Remote Method Invocation) Jedná se o distribuovaný objektový systém vyvinutý pouze pro jazyk Java (již od verze JDK 1.1). Pomocí tříd a jejich metod z balíčku java.rmi je možné realizovat klient – server aplikace bez nutnosti znalosti soketů a psaní relativně složitého kódu. Pro odstínění programátorů od sloožité práce a snížení nákladů na vývoj software byly vytvořeny knihovny implementující techniku volání procedur objektů umístěných na „vzdálených“ systémech. Poskytnutí této podporované techniky navíc zvýšilo atraktivitu platformy Java.
9
RMI
4.7.1 CORBA (Common Object Request Broker Architecture) Je to název pro jazykově neutrální a ucelené prostředí pro vývoj a použití distribuovaných objektově orientovaných aplikací, a to tentokrát bez ohledu na implementační jazyk, komunikační protokol a operační systém. Princip včetně pojmů je velmi podobný RMI.
Pojmy k zapamatování model TCP/IP, java.net, InetAddress, InetSocketAddress, rozsah portů, URL, ServerSocket, Socket, TCP soketová komunikace, sokety, accept(), zpracování více klientů, java.nio, buffery, síťové kanály, selektory, RMI, CORBA
Otázky pro zopakování 1. 2. 3. 4. 5. 6. 7.
Kolik vrstev používá model TCP/IP? Na jaké vrstvě probíhá soketová komunikace? Jak se jmenuje organizace pro zaregistrování nových portů? Na jakém portu „naslouchá“ zabezpečený webový server? Pro jaké přenosy je vhodná TCP komunikace? Kde musíme vytvořit objekt typu Socket? Jak vyřešíme souběžné obsloužení více klientů?
10
8. Jakou nevýhodu odstraňuje použití kanálů (nio)? 9. Jak se jmenuje metoda pro přetočení bufferu (nio)? 10. V souvislosti s jakým systémem-architekturou se objevuje slovo Skeleton?
Odkazy a další studijní prameny ZAKHOUR S. Java 6 Výukový kurz. Computer Press, Brno, 2007. http://www.root.cz/clanky/sitovani-v-jave-uvod/ http://www.root.cz/clanky/sitovani-v-jave-new-io/ http://java.sun.com/javase/6/docs/api/
11