13. diel - Java server - Propagácia lokálnou sieťou (3. časť)
V predchádzajúcom kvíze, Kvíz - Komunikačný protokol, Event bus a pluginy v Jave, sme si overili nadobudnuté skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Kvíz - Komunikačný protokol, Event bus a pluginy v Jave , sme naučili náš Java server ukazovať sa ďalším klientom v sieti. Dnes na túto komunikáciu naučíme našich klientov reagovať. Na strane klienta vytvoríme triedu, ktorá bude zachytávať údaje vysielané serverom.
Hľadanie lokálnych serverov
Nebude sa jednať o hľadaní v pravom slova zmysle, pretože servery budú
aktívne vysielať packety s informáciami o sebe. V module client
vytvoríme novú triedu LanServerFinder
, do ktorej naimplementujeme
príjem packetov zo servera.
Implementácia triedy
Triedu necháme len implementovať rozhranie Runnable
, aby si
klient mohol rozhodnúť sám, v akom vlákne kód pobeží:
public class LanServerFinder implements Runnable {}
Do triedy vložíme jednu inštančný premennú typu
MulticastSocket
:
private final MulticastSocket socket;
Na tomto socketu budeme prijímať datagramy zo servera.
Ďalej pridáme dve inštančné premenné:
private OnServerFoundListener serverFoundListener; private boolean interrupt = false;
Triedu OnServerFoundListener
vytvoríme za okamih. Premenná
interrupt
má rovnaký význam, ako v predchádzajúcich
lekciách.
Konštruktor triedy bude mať dva parametre: broadcastAddress
a
port
:
public LanServerFinder(InetAddress broadcastAddress, int port) throws IOException { this.socket = new MulticastSocket(port); this.socket.setSoTimeout(5000); this.socket.joinGroup(broadcastAddress); }
V konstruktoru vytvoríme novú inštanciu triedy
MulticastSocket
, ktorý bude počúvať na definovanom porte.
Metódou setSoTimeout()
hovoríme, že každých päť sekúnd sa
vyvolá výnimka SocketTimeoutException
. Pomocou metódy
joinGroup()
nastavíme broadcastové adresu socketu.
Do triedy pridáme jednu verejnú metódu shutdown()
, pomocou
ktorej budeme ukončovať beh vlákna:
public void shutdown() { interrupt = true; }
Ďalej pridáme Getter a setter pre listener
OnServerFoundListener
:
public OnServerFoundListener getServerFoundListener() { return serverFoundListener; } public void setServerFoundListener(OnServerFoundListener serverFoundListener) { this.serverFoundListener = serverFoundListener; }
Teraz konečne vytvoríme vnútorné rozhranie
OnServerFoundListener
:
@FunctionalInterface public interface OnServerFoundListener { void onServerFound(ServerStatusData data); }
Jedná sa o funkcionálne rozhranie s jednou metódou
onServerFound()
, ktorú budeme volať vždy, keď príde nový
datagram s informáciami o stave servera.
Nakoniec implementujeme metódu run()
:
@Override public void run() { final byte[] data = new byte[1024]; final DatagramPacket datagramPacket = new DatagramPacket(data, data.length); while(!interrupt) { try { socket.receive(datagramPacket); } catch (SocketTimeoutException e) { continue; } catch (IOException e) { break; } final ByteArrayInputStream bais = new ByteArrayInputStream( datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength()); try { final ObjectInputStream ois = new ObjectInputStream(bais); final ServerStatusMessage statusMessage = (ServerStatusMessage) ois.readObject(); final ServerStatusData statusData = (ServerStatusData) statusMessage.getData(); if (serverFoundListener != null) { serverFoundListener.onServerFound(statusData); } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
Na začiatku metódy sa inicializuje čítacie buffer data
na
veľkosť 1024
bajtov a príjmový datagramový packet
datagramPacket
. V nekonečnej slučke sa kontroluje, či ak sa
nemá vlákno vypnúť. Ak je nastavený príznak premenné
interrupt
na true
, ukončí sa nekonečná slučka a
tým aj vlákno, v ktorom tento kód bežal. V tele slučky sa zavolá metóda
receive()
, ktorá sa pokúsi prijať dáta zo servera. Metóda je
blokujúce, takže vlákno sa zablokuje na dobu, než prídu
dáta, alebo v našom prípade na dobu päť sekúnd, pretože
potom sa vyvolá výnimka SocketTimeoutException
. Po úspešnom
prijatí dát sa vytvorí nová inštancia triedy
ByteArrayInputStream
, do ktorej sa načítajú serializovaná dáta
o prijatej triede. Táto inštancia sa odovzdá ako parameter pri vytváraní
inštancie triedy ObjectInputStream
. Z
ObjectInputStream
u deserializujeme prijatú správu a přetypujeme
ju na triedu ServerStatusMessage
. Z tejto triedy získame triedu
ServerStatusData
. Nakoniec, ak bude nastavený
listener
, sa zavolá metóda onServerFound()
s
parametrom statusData
. Tým zabezpečíme, že trieda bude iba
prijímať datagramy, ale ich spracovanie nechá na inej triede.
Na otestovanie funkčnosti by mal mať čitateľ dostatočné vedomosti. Ak si s niečím nebudete vedieť rady, sú vám k dispozícii komentáre pod lekcií.
Týmto by sme mali uzavretú implementáciu propagácie servera v lokálnej sieti. Nabudúce, v lekcii Java server - Vylepšenie systému pluginov , ešte zostaneme v serverovej časti. Vylepšíme si systém pluginov o načítanie externých pluginov a implementujeme prioritné inicializáciu pluginov.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 19x (176.3 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java