Vánoční nadílka Vánoční nadílka
Vánoční akce! Daruj lepší budoucnost blízkým nebo sobě. Až +50 % zdarma na dárkové poukazy. Více informací

Lekce 13 - Java server - Propagace lokální sítí (3. část)

Java Server pro klientské aplikace Java server - Propagace lokální sítí (3. část)

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Java server - Propagace lokální sítí (2. část), jsme naučili náš Java server ukazovat se dalším klientům v síti. Dnes na tuto komunikaci naučíme naše klienty reagovat. Na straně klienta vytvoříme třídu, která bude zachytávat data vysílaná serverem.

Hledání lokálních serverů

Nebude se jednat o hledání v pravém slova smyslu, protože servery budou aktivně vysílat packety s informacemi o sobě. V modulu client vytvoříme novou třídu LanServerFinder, do které naimplementujeme příjem packetů ze serveru.

Implementace třídy

Třídu necháme pouze implementovat rozhraní Runnable, aby si klient mohl rozhodnout sám, v jakém vlákně kód poběží:

public class LanServerFinder implements Runnable {}

Do třídy vložíme jednu instanční proměnnou typu MulticastSocket:

private final MulticastSocket socket;

Na tomto socketu budeme přijímat datagramy ze serveru.

Dále přidáme dvě instanční proměnné:

private OnServerFoundListener serverFoundListener;
private boolean interrupt = false;

Třídu OnServerFoundListener vytvoříme za okamžik. Proměnná interrupt má stejný význam, jako v předchozích lekcích.

Konstruktor třídy bude mít dva parametry: 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 vytvoříme novou instanci třídy MulticastSocket, který bude poslouchat na definovaném portu. Metodou setSoTimeout() říkáme, že každých pět vteřin se vyvolá výjimka SocketTimeoutException. Pomocí metody joinGroup() nastavíme broadcastovou adresu socketu.

Do třídy přidáme jednu veřejnou metodu shutdown(), pomocí které budeme ukončovat běh vlákna:

public void shutdown() {
    interrupt = true;
}

Dále přidáme gettery a settery pro listener OnServerFoundListener:

public OnServerFoundListener getServerFoundListener() {
    return serverFoundListener;
}

public void setServerFoundListener(OnServerFoundListener serverFoundListener) {
    this.serverFoundListener = serverFoundListener;
}

Nyní konečně vytvoříme vnitřní rozhraní OnServerFoundListener:

@FunctionalInterface
public interface OnServerFoundListener {
    void onServerFound(ServerStatusData data);
}

Jedná se o funkcionální rozhraní s jednou metodou onServerFound(), kterou budeme volat vždy, když přijde nový datagram s informacemi o stavu serveru.

Nakonec implementujeme metodu 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čátku metody se inicializuje čtecí buffer data na velikost 1024 bajtů a příjmový datagramový packet datagramPacket. V nekonečné smyčce se kontroluje, zda-li se nemá vlákno vypnout. Pokud je nastaven příznak proměnné interrupt na true, ukončí se nekonečná smyčka a tím i vlákno, ve kterém tento kód běžel. V těle smyčky se zavolá metoda receive(), která se pokusí přijmout data ze serveru. Metoda je blokující, takže vlákno se zablokuje na dobu, než přijdou data, nebo v našem případě na dobu pět vteřin, protože poté se vyvolá výjimka SocketTimeoutException. Po úspěšném přijetí dat se vytvoří nová instance třídy ByteArrayInputStream, do které se načtou serializovaná data o přijaté třídě. Tato instance se předá jako parametr při vytváření instance třídy ObjectInputStream. Z ObjectInputStreamu deserializujeme přijatou zprávu a přetypujeme ji na třídu ServerStatusMessage. Z této třídy získáme třídu ServerStatusData. Nakonec, pokud bude nastavený listener, se zavolá metoda onServerFound() s parametrem statusData. Tím zajistíme, že třída bude pouze přijímat datagramy, ale jejich zpracování nechá na jiné třídě.

Na otestování funkčnosti by měl mít čtenář dostatečné znalosti. Pokud si s něčím nebudete vědět rady, jsou vám k dispozici komentáře pod lekcí.

Tímto bychom měli uzavřenou implementaci propagace serveru v lokální síti. Příště, v lekci Java server - Vylepšení systému pluginů, ještě zůstaneme v serverové části. Vylepšíme si systém pluginů o načítání externích pluginů a implementujeme prioritní inicializaci pluginů.


 

Stáhnout

Staženo 2x (154.76 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

 

Článek pro vás napsal Petr Štechmüller
Avatar
Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!
Autor se věnuje primárně programování v Jave, ale nebojí se ani webových technologií.
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!