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í ObjectOutputStream
u.
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 neseisSuccess()
- 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 21x (142.93 kB)
Aplikace je včetně zdrojových kódů v jazyce Java