Java: Síťová komunikace
Komunikovat mezi dvěma aplikacemi pomocí TCP socketů je v Javě velmi jednoduché a často využívané. V článku si ukážeme základy takové komunikace a vytvoříme si základní příklad, demonstrující aplikaci Klient-Server.
V Javě existují dvě základní možnosti jak mezi aplikacemi komunikovat na IP vrstvě.
- protokol TCP
- protokol UDP
Příjemné je, že jejich podpora je přímo součástí standardních knihoven.
Abychom identifikovali aplikaci na daném počítači, ke kterému se chceme připojovat, musíme počítače nějakým způsobem odlišit. V tomto případě je každé spojení charakterizováno IP adresou a portem, na kterém daná aplikace běží (server) nebo ke kterému se snaží připojit (klient).
Dále se nebudeme věnovat nepotvrzovanému UDP, ale pouze potvrzovanému TCP spojení, které je častěji používané.
Po spojení klienta a vytvoření jakési pomyslné cesty mezi serverem a klientem a můžeme mezi oběma aplikacemi komunikovat. Komunikace probíhá pomocí čtení a zápisu mezi datovými proudy.
Vytvořená aplikace se bude rozdělovat na část Server a Klient.
Server
Náš server, který si vytvoříme bude schopen komunikovat, tedy konkrétně bude schopen zobrazit data, která mu bude klient posílat.
Server vytváří novou instanci třídy ServerSocket, na určitém portu, který bude pro komunikaci používat. IP adresa, na kterém server poběží, je IP adresa daného počítače. Pro testování budete používat u klienta Loop-back IP 127.0.0.1 (logická smička, která representuje lokální počítač), na této IP adrese pojede i server, na stejném počítači:
1 |
ServerSocket sSocket=new ServerSocket(port); |
Port je integer proměnná a representuje číslo portu, na kterém server bude komunikovat (přijímat a odesílat požadavky).
Tímto je vytvořen nový ServerSocket, ke kterému je možné se připojit, ovšem bez dalších funkcí.
Pro čekání na připojení klienta využijeme funkci accept, která čeká na spojení s klientem a takovém úspěšném spojení vytváří proměnnou typu Socket, jež representuje konkrétní aktuální spojení s klientem:
1 |
Socket socket=sSocket.accept(); |
V tuto chvíli máme navázáno spojení s klientem a vytvořenou proměnnou typu Socket, reprezentující celé spojení. Ze socket proměnné můžeme lehce číst díky vytvoření InputStreamu, který proměnná může uvolnit:
1 |
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream())); |
Proměnná reader, typu BufferedReader, už umožňuje přímo klasické čtení, například pomocí readLine():
1 2 3 4 5 6 7 8 |
while ((request=reader.readLine())!=null){ try { System.out.println(request); } catch (NumberFormatException e) { return ; } } |
Proměnná reqeust je typu String a je do ní postupně ukládán řádek dat (textu), které klient odesílá.
Celé spojení, a vlastně celý server, ukončíme pomocí metody close()
1 2 |
if (!sSocket.isClosed()) sSocket.close(); |
Tím je hotová celá serverová část, která je schopna obsloužit pouze jednoho klienta. Abychom mohli obsluhovat klientů více, můžeme celý proces spouštět v nekonečné smyčce.
Zdrojový kód celé serverové částí si můžete stáhnout zde: Server.java.txt
Client
Pokud máme zpracovanou serverovou část, můžeme přejít ke klientské. Klient bude fungovat tak, že se pokusí navázat spojení se serverem na dané IP adrese a portu. Po spojení načte soubor s textem a tyto data odešle na server, který je zpracuje a vypíše.
Klient vytváří instanci třídy Socket, jehož parametry jsou IP adresa a port, na kterém čeká server na spojení (pro Loop-back to bude 127.0.0.1, jak jsem již zmínil u serverové části):
1 |
Socket socket = new Socket("127.0.0.1", port); |
Další operace fungují podobně jako u serverové části. Proměnnou socket jsme u serverové částí dostali pomocí metody accept, u klientské částí ji máme rovnou ze spojení.
U klientské částí, abychom mohli odesílat, musíme vytvořit PrintWriter, pro odesílání dat:
1 |
PrintWriter writer = new PrintWriter(socket.getOutputStream()); |
Jak bylo napsáno dříve, klient načte soubor s textem a ten odešle, takže dopíšeme otevření a načtení souboru. Data budeme odesílat pomocí vytvořeného PrintWriteru:
1 2 |
writer.println(line); writer.flush(); |
Celé zpracování a odeslání souboru může vypadat například takto:
1 2 3 4 5 6 7 8 |
BufferedReader reader = new BufferedReader(new InputStreamReader( input)); String line; //v cyklu odesle data while ((line = reader.readLine()) != null) { writer.println(line); writer.flush(); } |
Proměnná input je typu string a representuje cestu a název textového souboru pro odeslání.
Klienta a celé spojení ukončíme pomocí metody close:
1 |
writer.close(); |
Celou klientskou část si můžete prohlídnout zde: Client.java.txt
Závěrem
Toto je základní práce se síťovkou komunikací, kterou můžete v javě používat. Při troše přemýšlení jde tento ukázkový příklad velmi jednoduše předělat na jednoduchou aplikaci pro posílání zpráv mezi dvěma počítači, popřípadě přidělat obsluhu více klientů a obsluhovat je samostatně.
Jednoduché grafické rozhraní, které bylo použito u příkladu si můžete stáhnout zde: GUI.java.txt
bezva tutorial ale povedlo se mi navázat komunikaci jen s někým v mojí síti , jak se mám spojit s někým mimo tuto síť přes internet?
Na tohle by jsi potreboval verejnou IP adresu.
jo tak problém byl v nastavení mého routeru už mi to funguje
Ahoj, nemáš nějakej tip na článek o obousměrné komunikaci? Tedy aby server jak klient uměl vysílat a číst? On je to, řekl bych, dost zásadní rozdíl. Třeba mi vůbec nejde na jednom socketu vytvořit jak reader tak writer. To mám pro každou "zprávu" otvírat novej socket? Nehledě na to, že aby to fungovalo v reálným čase, tak to bude chtít na klient i server extra vlákno.
ahoj prosimte neměl bys nekde zdroják na clienta a servera bez toho gui?
Prece neni problem si to gui z kodu vymazat a nahradit cim potrebujes.
Čau,
může mi někdo poradit, proč mi to po stisku tlačítka Run Client vypíše chybu: Connection on port 81 refused! Is the server running there?
Server běží, a port je otevřen (ověřeno v cmd).
Nakopíroval jsem to přesně podle návodu.
Díky za odpověď
Dělá mě to stejný problém jako tobě
81 refused! Is the server running there?
vyřešil jsi to?
Občas jsou porty 0 – 1024 přístupné pouze správcům systému. Zkuste vyšší porty (třeba můj oblíbený 12345). Na 81 mě to taky odkoplo 😉
Dobrá práce, stručně a jasně.
Pomohl jste mi při semestrálce (šachy).
Děkuju. 🙂