Lekce 2 - Síť v Javě - Balíky pro síťovou komunikaci
V minulé lekci, Síť v Javě - Úvod, jsme si vysvětlili základní pojmy síťové komunikace v Javě, popsali si její techniky a seznámili se s terminologii.
Balíky Java pro síťovou komunikaci
Mezi základní balíky v Javě pro práci se síti můžeme zařadit:
java.net.*
java.io.*
java.nio.*
java.nio.channels.*
Existuje také balíček java.rmi s jehož pomocí je možné realizovat klient/server aplikace bez nutnosti znalosti socketů a psaní relativně složitého kódu. Pro odstínění programátorů od složité práce a snížení nákladů na vývoj softwaru byly vytvořeny knihovny implementující techniku volání procedur.
Základní balíčky si nyní popíšeme podrobněji:
Balíček java.net
Tento balíček je součástí java API už od své první verze. Poskytuje
podporu pro dva běžné síťové protokoly TCP a
UDP, které jsou vyžadovány pro komunikaci v rámci sítě.
Balíček java.net
tedy nabízí základní funkčnost pro
síťové aplikace, přičemž ji lze rozdělit do dvou částí:
- High Level API - Zabývájí se abstrakcí URI (Universal Resource Identifier), URL (Universal Resource Locator) a Connections, tj. připojení ke zdroji, na který odkazují URL.
- Nízkoúrovňové API - Zabývájí se abstrakcemi adres, tj. síťových identifikátorů, Sockets, tj. obousměrného mechanismu datové komunikace a Interfaces, tj. síťových rozhraní.
Kromě prostředků na spojově orientovanou a datagramovou komunikaci poskytuje balík také možnosti komunikace typu multicast, včetně metod pro připojování a odpojování se k jednotlivým multicast skupinám.
Třídy URL
a
URLConnection
Třída URL
v Javě je vstupním bodem ke všem dostupným
zdrojům na internetu. Adresa URL třídy popisuje Uniform Resource
Locator, což je signál pro „zdroj“ na World Wide Web. Zdroj
může označovat jednoduchý soubor nebo adresář, nebo může označovat
obtížnější objekt, jako je dotaz do databáze nebo na vyhledávač.
Třída URLConnection
v Javě je abstraktní třída
popisující připojení zdroje, jak je definováno podobnou URL. Třída
URLConnection
se používá pro pomoc se dvěma odlišnými, ale
vzájemně propojenými účely. Za prvé poskytuje kontrolu interakce se
serverem (zejména HTTP serverem) než třídou URL. Navíc s
URLConnection
může uživatel ověřit hlavičku přenesenou
serverem a může následně reagovat. Uživatel může také konfigurovat pole
záhlaví používaná v klientských požadavcích právě pomocí
URLConnection
.
Socket
a
ServerSocket
K realizaci spojení mezi dvěma aplikacemi jsou zapotřebí dva odlišné sockety. První čekající na příchozí spojení (serverový) a druhý, který musí spojení vytvořit (klientský).
K vytvoření klientského socketu (používá se ke komunikaci klienta)
slouží instance třídy Socket
. Prostřednictvím této třídy
můžeme číst a psát zprávy. K vytvoření serverového socketu (používá
se na straně serveru) slouží instance třídy ServerSocket
. Aby
se klientský socket mohl připojit, musí se konstruktoru třídy
Socket
předat adresa a port
cíle. Adresa může být instancí třídy String
anebo
instancí třídy InetAddress
. Adresa typu InetAddress
v sobě zapouzdřuje IP adresu cíle. Instance třídy InetAddress
se získá pomocí statické metody getByName(String host)
třídy
InetAddress
. Tato metoda na vstupu očekává buď IP nebo URL
adresu cíle.
Programováni socketu a práci s třídami URL
a
URLConnection
včetně použití třídy InetAddress
si ukážeme v některém z dalších článků.
Balíček java.io
Druhý balíček je rovněž součástí API od první verze. Obsahuje třídy pro práci s datovými proudy nebo třídy pro zpracování datových výstupů a vstupů.
Ve spojení se síťovou komunikací stojí za zmínku pouze vstupní
a výstupní proudy, které lze připojit na zdroj nebo cíl dat. Jsou
to ByteArrayInputStream
resp. ByteArrayOutputStream
.
Zabalíme-li tyto proudy pomocí DataInputStream
resp.
DataOutputStream
, mohou poskytovat způsob, jak přenášet
primitivní datové typy Javy. Ke všem ostatním zdrojům dat lze získat
přístup primitivními implementacemi tříd InputStream
resp.
OutputStream
.
Balíček java.nio
Nabízí nové přístupy pro práci se síťovými prostředky (sockety),
bez nutnosti tvorby vláken, umožňuje práci s tzv.
buffery. Jinými slovy balík nabízí pro každý primitivní
datový typ (kromě boolean
) třídy bufferů – jde o rychlejší
řešení než jsou klasické pole.
Hlavními prvky každého bufferu je jeho kapacita, pozice a mez. Kapacita udává maximální počet prvků, které buffer může obsahovat. Pozice je index aktuálního prvku, který má být čten nebo zapisován. Mez označuje index první pozice, kterou ještě nelze přečíst, nebo na kterou nelze zapsat:
Všechny buffery jsou zděděny od společné třídy
Buffer
.
Balíček
java.nio.channels
Obsahuje několik kanálů pro práci se sítí. Například
kanály pro práci s datagramy, se sockety, routy a další. Kanály společně
s buffery mohou nabízet totožnou funkčnost jako třídy
InputStream
a OutputStream
.
Z tohoto balíku si představíme pouze dvě třídy:
SocketChannel
- klientský kanálServerSocketChannel
- serverový kanál
Klientský kanál
Třída SocketChannel
v sobě zapouzdřuje klientský socket a
jeho využití je stejné jako instance třídy Socket
. Společně
s použitím Selektoru
a objektu ServerSocketChannel
umožňují vytvořit neblokující, bezvláknový server.
Instanci třídy SocketChannel
vytvoříme pomocí metody
open(SocketChannel remote)
- otevřeme kanál socketu a připojíme
se na adresu zadanou v parametru remote
. Zavoláme-li
open()
s prázdným parametrem, musíme později k připojení
socketu použít metodu connect(SocketAddres remote)
objektu
SocketChannel
:
Hlavní metody | Popis |
---|---|
public static SocketChannel open(SocketAddress remote) | Vytvoří instanci třídy SocketChannel , otevře kanál
socketu a připojí se na adresu zadanou v parametru remote . |
public static SocketChannel connect(SocketAddres remote) | Připojuje socket tohoto kanálu. Třída SocketAddress je
rodičovskou třídou . |
public void close() | Uzavře kanál. |
public int read(ByteBuffer dst) | Načítá data z kanálu do bufferu. Vrací počet načtených
dat. Vrátí-li hodnotu -1 , kanál byl uzavřen. |
public int write(ByteBuffer dst) | Zapisuje data z bufferu na kanál. Před jakýmkoli zápisem bufferu je
třeba volat metodu flip() , která ohraničí data v bufferu.
Metoda vrací počet zapsaných dat. |
Serverový kanál
Třída ServerSocketChannel
obsahuje metodu open()
vracející její instanci. Objekt vytvořený touto metodou ještě není
plnohodnotný serverový kanál. Aby byl kanál kompletní a byl schopný
naslouchat, je zapotřebí k němu přidružit objekt ServerSocket
získaný metodou socket()
a zavoláním jeho metody
bind(SocketAddress address, int port)
. Přijetí nového kanálu
příchozího klienta je realizováno metodou accept()
třídy
ServerSocektChannel
. Pomocí metody
configureBlocking(boolean block)
je vhodné nastavit serverovému
kanálu neblokující mód. Volba módu zásadně ovlivňuje metodu
accept()
. Bude-li nastaven neblokující mód, pak metoda
accept()
vrací buď SocketChannel
klienta nebo
null
a nijak neblokuje běh aplikace. Při blokujícím módu
metoda accept()
blokuje síťové vlákno do doby, dokud se na
server někdo nepřipojí. Po ukončení práce se serverem je zapotřebí
uzavřít ServerSocket
jeho vlastní metodou close()
a
ServerSocketChannel
také jeho vlastní metodou
close()
.
V příští lekci, Síť v Javě - Práce s URL, si popíšeme třídu java.net.URL včetně jejich hlavních metod a ukážeme si, jak je použít v praxi.