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

8. diel - Java server - Komunikačný protokol

V minulej lekcii, Java server - Zapisovacia vlákno , sme vylepšili odozvu servera pri zachovaní jeho funkčnosti. Dnes si navrhneme komunikačný protokol, pomocou ktorého budú komunikovať klient a server. Doteraz sme posielali textové správy, avšak nevedomky sme k tomu využívali posielanie kompletného objektu, nie len textu. Text sme mohli posielať, pretože triedu String možno serializovať a poslať po sieti.

Posielanie objektov

Java disponuje možnosťou posielať po sieti celej objekty. Tejto funkcie využijeme pri implementácii nášho komunikačného protokolu. Pre posielanie a príjem objektov slúžia triedy ObjectInputStream a ObjectOutputStream. Všetky objekty, ktoré budeme posielať, musí obsahovať konštantu serialVersionUID. Jedná sa o unikátne číslo, podľa ktorého sa budú objekty znova zostavovať na druhej strane linky. Obvykle IDE disponuje možnosťou toto číslo vygenerovať. Ďalej musí všetky tieto objekty implementovať rozhranie Serializable. Jedná sa len o značkovacia rozhranie, takže nevyžaduje implementovať žiadne metódy. Je to informácia pre JVM, že takéto objekty je možné serializovať a poslať po sieti.

Komunikačný protokol

Všetky triedy, ktoré budeme vytvárať, sa budú nachádzať v module share. To preto, aby k nim mal prístup ako modul client, tak modul server. V module share, v priečinku src/main/java/, založte balík, ktorý zodpovedá celému projektu, v mojom prípade je to: cz.stechy.chat. V tomto balíčku vytvorte balíček net.message, v ktorom budeme uchovávať všetky triedy pre komunikáciu medzi klientom a serverom. V tomto balíčku založíme rozhranie, ktoré bude reprezentovať samotnú správu IMessage. Rozhranie necháme dediť od rozhrania Serializable, aby sme nemuseli toto rozhranie implementovať v konkrétnych triedach a mali istotu, že triedu pôjde odoslať pomocou ObjectOutputStream u.

public interface IMessage extends Serializable {
    String getType();
    Object getData();

    default boolean isSuccess() {
        return true;
    }
}

Rozhranie obsahuje tri metódy:

  • getType() - vráti typ správy; každý typ bude zodpovedať jednej triede
  • getData() - vráti dáta, ktoré správa nesie
  • isSuccess() - informácie, či ak sa požadovaná akcia vykonala v poriadku, alebo skončila neúspechom

Rovno si vytvoríme jednoduchú implementáciu rozhrania IMessage, pomocou ktorej budeme opäť schopní odosielať textové správy:

public class TextMessage implements IMessage {
    public static final String MESSAGE_TYPE = "text";
    private final String data;

    public TextMessage(String data) {
        this.data = data;
    }

    @Override
    public String getType() {
        return "text";
    }

    @Override
    public Object getData() {
        return data;
    }
}

Implementácie protokolu

Keď sme nadefinovali základné triedu, ktorú budeme posielať po sieti, je potrebné upraviť všetky miesta v kóde, kde odosielame alebo prijímame dáta typu Object, na dátový typ IMessage.

Rozhranie, kde musíme zmeniť dátový typ, sú:

  • IClient
    • void sendMessageAsync(IMessage message);
    • void sendMessage(IMessage message) throws IOException;
  • IWriterThread
    • void sendMessage(ObjectOutputStream writer, IMessage message);
Podľa rozhrania upravte aj implementácia metód v zodpovedajúcich triedach.

V triede Client je potreba upraviť prijímanie správ:

IMessage received;
while ((received = (IMessage) reader.readObject()) != null) {}

Teraz už neprijímame triedu Object, ale rozhranie IMessage. Pretypovanie je tu na mieste, pretože náš protokol stojí na myšlienke, že všetky objekty, ktoré pošleme budú mať spoločné rozhranie práve IMessage.

V triede ClientDispatcher musíme upraviť odosielaní správy, využijeme triedu TextMessage:

client.sendMessage(new TextMessage("count: " + count));

Testovanie funkčnosti

Konečne sa pozrieme, či ak naša doterajšia práca bola úspešná a otestujeme, či je server schopný komunikovať s klientom.

V module client vytvoríme opäť zodpovedajúce balíček a v ňom triedu SimpleClient. Trieda bude mať iba jednu metódu main(), v ktorej nadviažeme spojenie so serverom, odošleme dáta, počkáme, až príde odpoveď a spojenie ukončíme:

public class SimpleClient {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 15378);
        Thread.sleep(1000);
        ObjectOutputStream writer = new ObjectOutputStream(socket.getOutputStream());
        writer.writeObject(new TextMessage("Hello from client."));
        writer.flush();
        ObjectInputStream reader = new ObjectInputStream(socket.getInputStream());
        System.out.println(((IMessage) reader.readObject()).getData().toString());
        socket.close();
    }
}

Spustite najskôr server a potom klienta. Výsledkom by malo byť vypísanie správy "Hello from client".

To by bolo pre dnešné kratšie lekciu všetko. Nabudúce, v lekcii Java server - Event bus , si naimplementujeme jednoduchú event bus.


 

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é 20x (142.93 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java

 

Predchádzajúci článok
Java server - Zapisovacia vlákno
Všetky články v sekcii
Server pre klientskej aplikácie v Jave
Preskočiť článok
(neodporúčame)
Java server - Event bus
Č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