Java (18) - síťová komunikace I.
Jestliže jsem minule zdůrazňoval důležitost práce se soubory, nyní přijde na řadu možná ještě důležitější téma - výměna dat po síti. Podpora TCP/IP (včetně IPv6) je v Javě na výborné úrovni.
21.9.2005 06:00 |
Lukáš Jelínek
| Články autora
| přečteno 45202×
Doba síťová
Dnešní dobu lze bez nadsázky označit za období síťové komunikace. Význam
dálkového přenosu dat stále vzrůstá, proto je i v Javě věnována této oblasti
mimořádná pozornost. Je to důležité hlavně proto, že právě sítě jsou častým
místem pro nasazení Javy, ať pro stranu serverovou nebou klientskou.
Z tohoto důvodu jsem se rozhodl věnovat se této oblasti už nyní, v souvislosti
se vstupně/výstupními operacemi. Začneme samozřejmě úplnými základy, tedy
tím, jaká je vůbec filosofie síťové komunikace v Javě, jak se navazuje spojení,
jak jsou reprezentovány adresy apod. "Vyšší stupeň" síťové komunikace (tedy
podporu vzdáleného zpracování dat, přístup do databází, distribuované
zpracování dat atd.) si necháme na později.
Základy síťové komunikace
Pro další výklad budu předpokládat, že čtenáři znají základy technologie
TCP/IP verze 4, tedy zejména způsob reprezentace adres, základní vlastnosti
jednotlivých komunikačních protokolů, mechanismus navazování a ukončování
spojení atd., bude se to totiž zatraceně hodit. Protože IP verze 6 je poměrně
nová záležitost, a zatím se moc nepoužívá, budu při popisu používat (tam, kde
na tom záleží) vždy verzi 4 a o odlišnostech verze 6 se zmíním (většina
API však verzi vůbec nerozlišuje). Nyní ještě raději velice stručně obecný
úvod do TCP/IP:
Datagramová komunikace
Začneme tím jednodušším, datagramovou komunikací (reprezentovanou zde
protokolem UDP). Kdo tuto komunikaci zná, tak ví, že vytvoříme balík dat
(paket, datagram) a ten odešleme na nějaký (jiný, ale klidně i tentýž)
počítač. Zde ho může (ale také nemusí) někdo očekávat - pokud ho nějaký
program očekává, naslouchá na tzv. portu, a když mu data přijdou, zpracuje je.
Komunikace probíhá prostřednictví naprosto nezávislých datagramů, které
odesílatel posílá v dobré víře, že je někdo přijme a zpracuje. Není nijak
zajištěno, že datagram dojde v pořádku (resp. že vůbec dojde), ani že datagramy
přijdou v pořadí, v jakém se odesílaly. Pokud je to nutné, musí si tyto
mechanismy zajistit příslušné aplikace.
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 třeba pro vzdálené volání
procedur (RPC).
Spojová komunikace
Vyšším stupněm je spojová komunikace, zde protokolem TCP. Mezi počítači
(přesněji řečeno porty na počítačích) se vytvoří komunikační kanál, který
je zabezpečený z hlediska poškození nebo ztráty dat, a zaručuje správné
pořadí přenášených dat. Data se sice posílají v paketech, ale to je aplikačním
programům prakticky skryto. Před použitím je nutno komunikační kanál vytvořit,
co předpokládá, aby jeden z komunikujících programů naslouchal na příslušném
portu a druhý se na tento port připojil.
Spojovou komunikaci používá většina aplikací, jmenovitě třeba HTTP, FTP,
poštovní protokoly (SMTP, POP3, IMAP4), telnet a SSH apod.
Adresy a porty v Javě
Než začneme komunikovat, musíme nejdřív vědět s kým. Proto je důležité vědět,
jak se v Javě pracuje s adresami a porty. Není to nic těžkého, dokonce se dá
říct, že oproti jiným jazykům (třeba C/C++) máme hodně práce usnadněno.
Reprezentace IP adres
Většina základních síťových záležitostí se nachází v balíku java.net . Tam
také najdeme třídu InetAddress , která představuje obecnou IP adresu.
V dřívějších verzích znamenala automaticky adresu IP verze 4, to už ale
neplatí - existují potomci pro jednotlivé protokoly (Inet4Address a
Inet6Address ). Pro většinu použití na verzi nezáleží, proto metody
přijímají instance této obecnější třídy.
Všechny uvedené třídy se vyznačují tím, že nemají žádný veřejný konstruktor.
Instance se vytvářejí statickými metodami a lze přitom použít některou z
následujících cest:
- číselná reprezentace adresy - použije se metoda
getByAddress(byte[] addr) ,
která vytvoří instanci adresy IPv4 (předá-li se pole 4 hodnot) nebo
IPv6 (pro pole 16 hodnot). Adresa se použije tak, jak je, žádný zpětný převod
na jméno se nedělá. Pořadí bajtů je takové, jak jsme zvyklí (tedy
nejvýznamnější bajt jako první).
- číselná + jmenná reprezentace - metoda
getByAddress(String host, byte[] addr) . Umožňuje vycházet z číselné
reprezentace s tím, že se uvede i jmenná adresa, aniž by se přitom prováděl
DNS dotaz. Používání tohoto postupu je lépe se vyhnout.
- jmenná reprezentace - adresa se zadá obvyklým způsobem metodě
getByName(String host) , ta provede DNS dotaz (přesněji řečeno, dotáže se
systému, který může převody jmenných adres na číselné provádět různě)
a vrátí instanci objektu Inet4Address nebo Inet6Address . Místo jmenné
adresy lze uvést i číselnou (v textovém tvaru), ta se pak přímo použije
(jako při volání metody getByAddress() ).
- získání lokální adresy - pokud potřebujeme lokální adresu, použijeme
metodu
getLocalHost() . Ovšem pozor, nemůžeme ovlivnit, kterou z lokálních
adres metoda vrátí (pokud má počítač víc síťových rozhraní, může to
být dost nepříjemné).
Vytvořená instance je neměnná. Adresa obecně nemusí znamenat pouze jediný
cíl (unicast), ale může být i typu multicast. Zvláštním případem je tzv.
nespecifikovaná (též anylocal) adresa, která se nesmí použít pro určení cíle,
ale má význam při přidělování lokálních adres (říká, že lze použít libovolnou
místní adresu, tedy i libovolné rozhraní).
Instance třídy InetAddress není pouze "kontejner na pár bajtů", ale má také
vlastní funkcionalitu. Lze provádět reverzní DNS dotazy (getHostName() a
getCanonicalHostName() ) a dokonce zjistit dosažitelnost daného stroje
(voláním některou z metod isReachable() ; ovšem pozor na to, že správce
zkoumaného cíle mohl používané služby, tedy ICMP ECHO a TCP ECHO, na
firewallu zablokovat (tyto metody jsou k dispozici od JDK 1.5).
Jak se s objekty InetAddress pracuje, ukazuje příklad:
byte ip4[] = { 82, 208, 29, 37 }; // adresa IPv4
try {
InetAddress ia = InetAddress.getByAddress(ip4);
InetAddress ia2 = InetAddress.getByName("82.208.29.37");
InetAddress ia3 = InetAddress.getByName("www.linuxsoft.cz");
InetAddress ia4 = InetAddress.getByAddress("www.linuxsoft.cz", ip4);
InetAddress local = InetAddress.getLocalHost(); // místní adresa
System.out.println(ia.getCanonicalHostName());
if (!ia.isReachable(5000)) System.err.println("Stroj je nedostupny");
} catch (UnknownHostException e) {
e.printStackTrace();
}
Je to snad dostatečně zřejmé. První čtyři volání statických metod budou mít
(pokud vše půjde, jak má) za následek vytvoření stejné instance (předpokládám,
že www.linuxsoft.cz má jedinou IP adresu). Jinak by tomu bylo v situaci, když
by např. nefungovala správně služba DNS - pak by třetí volání selhalo.
Získání lokální adresy je jasné, stejně jako vypsání kanonického názvu
pro první vytvořenou instanci (opět musí fungovat DNS). Poslední volání pak
otestuje dostupnost daného stroje (s timeoutem 5 sekund).
Čísla portů
Jak známo, čísla portů jsou šestnáctibitová, tedy v rozsahu 0-65535. V Javě
však používáme k jejich reprezentaci typ int , tedy číslo s mnohem větším
rozsahem. Proto musíme dát pozor, abychom používali pouze platné hodnoty
(pokud si pozor nedáme, dočkáme se obvykle výjimky IllegalArgumentException ).
Úplná specifikace
Máme k dispozici i třídu, která sdružuje adresu a číslo portu do jediného
objektu. Je to třída InetSocketAddress (je potomkem abstraktní třídy
SocketAddress ; to má svůj smysl, protože jako argument metod obvykle
figuruje tato nadtřída, což umožňuje univerzálnější použití, třeba i pro
jiné komunikační protokoly), vytvářená obvykle normálním způsobem, tj.
voláním konstruktoru (kterému předáme potřebné informace).
Zvláštním způsobem vytvoření je zavolání statické metody createUnresolved (),
která je k dispozici od JDK 1.5. Ta vytvoří instanci podle jmenné adresy,
kterou se nesnaží přeložit na číselnou. To se hodí pro případy, kdy není
k dispozici DNS, ale můžeme využít proxy server.
Následující příklad ukazuje různé cesty vytvoření objektů
IP adresy s číslem portu:
try {
// vytvoření z instance přeložené IP adresy
InetAddress ia = InetAddress.getByName("www.linuxsoft.cz");
InetSocketAddress isa = new InetSocketAddress(ia, 80);
// dtto, ale nevyhazuje se výjimka při chybě DNS
InetSocketAddress isa2 = new InetSocketAddress("www.linuxsoft.cz", 80);
// nepřeložená adresa
InetSocketAddress isa4 = InetSocketAddress.createUnresolved("www.linuxsoft.cz", 80);
// nespecifikovaná adresa, automatický port
InetSocketAddress isa3 = new InetSocketAddress(0);
} catch (UnknownHostException e) {
e.printStackTrace();
}
První cestou je vytvořit instanci InetAddress a na jejím základě pak instanci
adresy s portem. Druhá cesta (tedy předání jmenné adresy přímo konstruktoru
InetSocketAddress ) funguje podobně, avšak s tím rozdílem, že pokud se nepodaří
jmennou adresu přeložit, nevyhodí se žádná výjimka a adresa zůstane nepřeložená.
V této chybové situaci to tedy dopadne přesně tak, jak to udělá třetí z cest,
tedy vytvoření nepřeložené adresy. A konečně poslední cestou je vytvoření
nespecifikované ("wildcard") adresy, která se používá ve smyslu libovolné
místní zdrojové adresy - zadává se pouze číslo portu. Ale v příkladu je jako
toto číslo uvedena nula, která má zvláštní význam: systém přiřadí číslo
zdrojového portu automaticky.
Síťová rozhraní
Jak jsem se zmínil v odstavci o získání lokální adresy, uvedená metoda
neumožňuje určit, ke kterému síťovému rozhraní má daná adresa patřit
- v počítači může být těchto rozhraní (síťových karet, modemů apod.) větší
počet. Přesto ale nejsme zbaveni možnosti určit, se kterým rozhraním se bude
pracovat. Máme totiž třídu NetworkInterface .
Rozhraní můžeme určit buď podle jeho IP adresy, anebo podle názvu zařízení,
např. eth0 (to je sice platformově závislá věc, ale v mnoha případech jiné
cesty není). Instance objektu se vytvářejí statickými metodami
getByInetAddress() a getByName() (veřejné konstruktory nejsou k dispozici).
Můžeme také zavolat metodu getNetworkInterfaces() , čímž získáme všechna
aktivní rozhraní.
Hlavním smyslem třídy NetworkInterface je získání místní IP adresy.
Je třeba si uvědomit, že každé rozhraní může mít přiřazeno
více IP adres - k jejich zjištění slouží metoda getInetAddresses() , která
vrátí jejich seznam. Pak už s nimi můžeme pracovat dle libosti. Více ukáže
příklad:
try {
// rozhraní identifikované názvem
NetworkInterface ni = NetworkInterface.getByName("eth0");
// zpracování seznamu IP adres k rozhraní
Enumeration<InetAddress> adr = ni.getInetAddresses();
while (adr.hasMoreElements()) {
InetAddress ia = adr.nextElement();
...
}
} catch (SocketException e) {
e.printStackTrace();
}
Z příkladu je jasně vidět, jak se získá přístup k rozhraní identifikovanému
svým názvem, a jak se pak pracuje se seznamem IP adres, které má rozhraní
přiřazeno. Většinou je tato adresa jediná, ale musíme počítat s tím, že jich
může být víc, ale nemusí být také žádná (třeba při chybě v konfiguraci sítě).
Komunikujeme
Toto bylo nutné minimum, bez kterého se nelze obejít při jakékoli síťové
komunikaci. Zatím jsme ještě nekomunikovali, ale k tomu se dostaneme příště.
Budeme posílat UDP datagramy a navazovat spojení protokolem TCP.
Verze pro tisk
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|