IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 8 - Java server - Komunikační protokol

V předchozím kvízu, Kvíz - Správa klientů a spojení, zapisovací vlákno v Javě, jsme si ověřili nabyté zkušenosti z předchozích lekcí.

Dnes si navrhneme komunikační protokol, pomocí kterého budou komunikovat klient a server. Dosud jsme posílali textové zprávy, ovšem nevědomky jsme k tomu využívali posílání kompletního objektu, ne jen textu. Text jsme mohli posílat, protože třídu String lze serializovat a poslat po síti.

Posílání objektů

Java disponuje možností posílat po síti celé objekty. Této funkce využijeme při implementaci našeho komunikačního protokolu. Pro posílání a příjem objektů slouží třídy ObjectInputStream a ObjectOutputStream. Všechny objekty, které budeme posílat, musí obsahovat konstantu serialVersionUID. Jedná se o unikátní číslo, podle kterého se budou objekty znovu sestavovat na druhé straně linky. Obvykle IDE disponuje možností toto číslo vygenerovat. Dále musí všechny tyto objekty implementovat rozhraní Serializable. Jedná se pouze o značkovací rozhraní, takže nevyžaduje implementovat žádné metody. Je to informace pro JVM, že takovéto objekty je možné serializovat a poslat po síti.

Komunikační protokol

Všechny třídy, které budeme vytvářet, se budou nacházet v modulu share. To proto, aby k nim měl přístup jak modul client, tak modul server. V modulu share, ve složce src/main/java/, založte balíček, který odpovídá celému projektu, v mém případě je to: cz.stechy.chat. V tomto balíčku vytvořte balíček net.message, ve kterém budeme uchovávat veškeré třídy pro komunikaci mezi klientem a serverem. V tomto balíčku založíme rozhraní, které bude reprezentovat samotnou zprávu IMessage. Rozhraní necháme dědit od rozhraní Serializable, abychom nemuseli toto rozhraní implementovat v konkrétních třídách a měli jistotu, že třídu půjde odeslat pomocí ObjectOutputStreamu.

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

    default boolean isSuccess() {
        return true;
    }
}

Rozhraní obsahuje tři metody:

  • getType() - vrátí typ zprávy; každý typ bude odpovídat jedné třídě
  • getData() - vrátí data, která zpráva nese
  • isSuccess() - informace, zda-li se požadovaná akce vykonala v pořádku, nebo skončila neúspěchem

Rovnou si vytvoříme jednoduchou implementaci rozhraní IMessage, pomocí které budeme opět schopni odesílat textové zprá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;
    }
}

Implementace protokolu

Když jsme nadefinovali základní třídu, kterou budeme posílat po síti, je potřeba upravit všechna místa v kódu, kde odesíláme nebo přijímáme data typu Object, na datový typ IMessage.

Rozhraní, kde musíme změnit datový typ, jsou:

  • IClient
    • void sendMessageAsync(IMessage message);
    • void sendMessage(IMessage message) throws IOException;
  • IWriterThread
    • void sendMessage(ObjectOutputStream writer, IMessage message);

Podle rozhraní upravte i implementace metod v odpovídajících třídách.

V třídě Client je potřeba upravit přijímání zpráv:

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

Nyní již nepřijímáme třídu Object, ale rozhraní IMessage. Přetypování je zde na místě, protože náš protokol stojí na myšlence, že všechny objekty, které pošleme budou mít společné rozhraní právě IMessage.

V třídě ClientDispatcher musíme upravit odesílání zprávy, využijeme třídu TextMessage:

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

Testování funkčnosti

Konečně se podíváme, zda-li naše dosavadní práce byla úspěšná a otestujeme, zda-li je server schopný komunikovat s klientem.

V modulu client vytvoříme opět odpovídající balíček a v něm třídu SimpleClient. Třída bude mít pouze jednu metodu main(), ve které navážeme spojení se serverem, odešleme data, počkáme, až přijde odpověď a spojení 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();
    }
}

Spusťte nejdříve server a pak klienta. Výsledkem by mělo být vypsání zprávy "Hello from client".

To by bylo pro dnešní kratší lekci vše.

Příště, v lekci Java server - Event bus, si naimplementujeme jednoduchou event bus.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

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

 

Předchozí článek
Kvíz - Správa klientů a spojení, zapisovací vlákno v Javě
Všechny články v sekci
Server pro klientské aplikace v Javě
Přeskočit článek
(nedoporučujeme)
Java server - Event bus
Článek pro vás napsal Petr Štechmüller
Avatar
Uživatelské hodnocení:
1 hlasů
Autor se věnuje primárně programování v Javě, ale nebojí se ani webových technologií.
Aktivity