IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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

 

Predchádzajúci článok
Kvíz - Komunikačný protokol, Event bus a pluginy v Jave
Všetky články v sekcii
Server pre klientskej aplikácie v Jave
Preskočiť článok
(neodporúčame)
Java server - Vylepšenie systému pluginov
Článok pre vás napísal Petr Štechmüller
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje primárně programování v Javě, ale nebojí se ani webových technologií.
Aktivity