Písanie kódu, ktorý sa vykonáva na určitom zariadení, je veľmi uspokojujúce. Napísanie kódu, ktorý sa spustí na niekoľkých zariadeniach, ktoré navzájom komunikujú, však jednoducho potvrdzuje život. Tento článok vás naučí, ako sa pripojiť a vymieňať si správy prostredníctvom siete pomocou protokolu TCP (Transmission Control Protocol).
V tomto článku nastavíte aplikáciu, ktorá k vám pripojí počítač a v podstate ho zblázni - hovorte so sebou. Dozviete sa tiež rozdiel medzi dvoma najpoužívanejšími streammi na vytváranie sietí v Jave a ich fungovaním.
Dátové a objektové toky
Pred ponorením sa do kódu je potrebné rozlíšiť rozdiel medzi dvoma prúdmi použitými v článku.
Dátové toky
Dátové toky spracovávajú primitívne dátové typy a reťazce. Údaje odosielané cez dátové toky je potrebné ručne serializovať a deserializovať, čo sťažuje prenos komplexných údajov. Dátové toky však môžu komunikovať so servermi a klientmi napísanými v iných jazykoch ako Java. Surové toky sú v tomto aspekte podobné dátovým tokom, ale dátové toky zaisťujú, že údaje sú formátované spôsobom nezávislým na platforme, čo je výhodné, pretože obe strany budú schopné čítať odoslané údaje.
Objektové toky
Objektové toky spracovávajú primitívne dátové typy a objekty, ktoré implementujú
Serializovateľné
rozhranie. Údaje odosielané cez prúdy objektov sa automaticky serializujú a deserializujú, čo uľahčuje prenos komplexných údajov. Objektové toky však môžu komunikovať iba so servermi a klientmi napísanými v jazyku Java. Tiež,
ObjectOutputStream
pri inicializácii odošle hlavičku do súboru
InputStream
druhej strany, ktorá pri inicializácii blokuje vykonanie, kým nie je prijatá hlavička.
Kroky
Krok 1. Vytvorte triedu
Vytvorte triedu a pomenujte ju, ako chcete. V tomto článku bude pomenovaný
NetworkAppExample
verejná trieda NetworkAppExample {}
Krok 2. Vytvorte hlavnú metódu
Vytvorte hlavnú metódu a deklarujte, že môže vyvolávať výnimky z
Výnimka
typu a akejkoľvek jeho podtriedy - všetky výnimky. Toto je považované za zlú prax, ale je prijateľné pre barebone príklady.
public class NetworkAppExample {public static void main (String args) throws Exception {}}
Krok 3. Deklarujte adresu servera
V tomto prípade sa použije adresa lokálneho hostiteľa a ľubovoľné číslo portu. Číslo portu musí byť v rozsahu od 0 do 65535 (vrátane). Čísla portov, ktorým sa treba vyhnúť, sa však pohybujú od 0 do 1023 (vrátane), pretože ide o vyhradené systémové porty.
public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; }}
Krok 4. Vytvorte server
Server je viazaný na adresu a port a počúva prichádzajúce pripojenia. V Jave,
ServerSocket
predstavuje koncový bod na strane servera a jeho funkciou je prijímanie nových pripojení.
ServerSocket
nemá toky na čítanie a odosielanie údajov, pretože nereprezentuje spojenie medzi serverom a klientom.
import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); }}
Krok 5. Začiatok servera denníka
Na účely protokolovania vytlačte na konzolu, že server bol spustený.
import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); }}
Krok 6. Vytvorte klienta
Klient je viazaný na adresu a port servera a po nadviazaní spojenia počúva pakety (správy). V Jave,
Zásuvka
predstavuje buď koncový bod na strane klienta pripojený k serveru, alebo pripojenie (zo servera) ku klientovi, a slúži na komunikáciu so stranou na druhom konci.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); }}
Krok 7. Pokus o pripojenie
Na účely protokolovania vytlačte na konzolu, že sa pokúsilo o pripojenie.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); }}
Krok 8. Vytvorte pripojenie
Klienti sa nikdy nepripoja, pokiaľ server nepočúva a neprijíma, inými slovami, nadväzuje pripojenia. V Jave sa spojenia nadväzujú pomocou
súhlasiť()
metóda
ServerSocket
trieda. Metóda zablokuje spustenie, kým sa klient nepripojí.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); }}
Krok 9. Zaznamenať nadviazané pripojenie
Na účely protokolovania vytlačte na konzolu, že bolo nadviazané spojenie medzi serverom a klientom.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); }}
Krok 10. Pripravte komunikačné toky
Komunikácia prebieha cez toky a v tejto aplikácii musia byť surové toky (pripojenie z) servera (ku klientovi) a klientovi reťazené buď do dátových alebo objektových tokov. Nezabudnite, že obe strany musia používať rovnaký typ streamu.
-
Dátové toky
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); }}
-
Objektové toky
Keď sa používa viac objektových prúdov, vstupné toky sa musia inicializovať v rovnakom poradí ako výstupné toky, pretože
ObjectOutputStream
pošle hlavičku druhej strane a
ObjectInputStream
blokuje spustenie, kým neprečíta hlavičku.
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); }}
Poradie podľa vyššie uvedeného kódu môže byť jednoduchšie na zapamätanie - najskôr inicializujte výstupné toky a potom vstupné toky v rovnakom poradí. Ďalší príkaz na inicializáciu prúdov objektov je však nasledujúci:
ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ());
Krok 11. Zaznamenajte, že komunikácia je pripravená
Na účely protokolovania vytlačte na konzolu, že komunikácia je pripravená.
// vynechaný kód import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); // vynechaný kód System.out.println ("Komunikácia je pripravená."); }}
Krok 12. Vytvorte správu
V tejto aplikácii,
Ahoj Svet
text bude odoslaný na server buď ako
bajt
alebo
Reťazec
. Deklarujte premennú typu, ktorý závisí od použitého streamu. Použite
bajt
pre dátové toky a
Reťazec
pre toky objektov.
-
Dátové toky
Serializácia sa pomocou dátových tokov vykonáva prevodom objektov na primitívne dátové typy alebo
Reťazec
. V tomto prípade,
Reťazec
sa prevádza na
bajt
namiesto písomného použitia
writeBytes ()
metóda, ktorá ukazuje, ako by sa to robilo s inými objektmi, ako sú obrázky alebo iné súbory.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); byte messageOut = "Hello World".getBytes (); }}
-
Objektové toky
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); String messageOut = "Hello World"; }}
Krok 13. Odošlite správu
Zapisujte údaje do výstupného toku a vypláchnite tok, aby ste sa presvedčili, že údaje boli úplne zapísané.
-
Dátové toky
Najprv je potrebné odoslať dĺžku správy, aby druhá strana vedela, koľko bajtov potrebuje na prečítanie. Potom, čo je dĺžka odoslaná ako primitívny celočíselný typ, je možné odoslať bajty.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektové toky
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Krok 14. Protokol odoslanej správy
Na účely protokolovania vytlačte správu, ktorá bola odoslaná, do konzoly.
-
Dátové toky
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + nový reťazec (messageOut)); }}
-
Objektové toky
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + messageOut); }}
Krok 15. Prečítajte si správu
Čítajte údaje zo vstupného toku a prevádzajte ich. Keďže presne poznáme typ odosielaných údajov, vytvoríme buď a
Reťazec
od
bajt
alebo obsadenie
Objekt
do
Reťazec
bez kontroly, v závislosti od použitého streamu.
-
Dátové toky
Keďže bola najskôr odoslaná dĺžka a potom bajty, čítanie sa musí vykonať v rovnakom poradí. V prípade, že je dĺžka nulová, nie je čo čítať. Objekt sa deserializuje, keď sa bajty prevedú späť na inštanciu, v tomto prípade z
Reťazec
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + nový reťazec (messageOut)); int dĺžka = serverIn.readInt (); if (dĺžka> 0) {byte messageIn = nový bajt [dĺžka]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektové toky
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + messageOut); Reťazec messageIn = (Reťazec) serverIn.readObject (); }}
Krok 16. Protokol o prečítaní správy
Na účely protokolovania vytlačte na konzolu prijatú správu a vytlačte jej obsah.
-
Dátové toky
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); DataOutputStream clientOut = nový DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nový DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nový DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nový DataInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + nový reťazec (messageOut)); int dĺžka = serverIn.readInt (); if (dĺžka> 0) {byte messageIn = nový bajt [dĺžka]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Správa prijatá od klienta:" + nový reťazec (messageIn)); }}}
-
Objektové toky
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); ObjectOutputStream clientOut = nový ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nový ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nový ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nový ObjectInputStream (connection.getInputStream ()); System.out.println („Komunikácia je pripravená.“); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Správa odoslaná na server:" + messageOut); Reťazec messageIn = (Reťazec) serverIn.readObject (); System.out.println ("Správa prijatá od klienta:" + messageIn); }}
Krok 17. Odpojte pripojenia
Pripojenie sa preruší, keď jedna strana zavrie svoje streamy. V Jave sa zatvorením výstupného toku zatvorí aj príslušný soket a vstupný tok. Akonáhle strana na druhom konci zistí, že pripojenie je mŕtve, musí tiež zavrieť svoj výstupný tok, aby sa zabránilo úniku pamäte.
// vynechaný kód import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); // vynechaný kód System.out.println ("Komunikácia je pripravená."); // kód vynechaný clientOut.close (); serverOut.close (); }}
Krok 18. Odpojenie denníka
Na účely protokolovania boli odpojené pripojenia k tlači na konzole.
// vynechaný kód import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); // vynechaný kód System.out.println ("Komunikácia je pripravená."); // kód vynechaný clientOut.close (); serverOut.close (); System.out.println („Pripojenia uzavreté.“); }}
Krok 19. Ukončite server
Pripojenia sú odpojené, ale server je stále v prevádzke. Ako
ServerSocket
nie je spojený so žiadnym streamom, treba ho výslovne zavrieť volaním
Zavrieť()
metóda.
// vynechaný kód import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); // vynechaný kód System.out.println ("Komunikácia je pripravená."); // kód vynechaný clientOut.close (); serverOut.close (); System.out.println („Pripojenia uzavreté.“); server.close (); }}
Krok 20. Protokol servera denníka
Na účely protokolovania bola tlač na server konzoly ukončená.
// vynechaný kód import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket server = nový ServerSocket (port, 50, InetAddress.getByName (hostiteľ)); System.out.println ("Server spustený."); Socket client = nový Socket (hostiteľ, port); System.out.println ("Pripojenie k serveru …"); Soketové pripojenie = server.accept (); System.out.println ("Pripojenie nadviazané."); // vynechaný kód System.out.println ("Komunikácia je pripravená."); // kód vynechaný clientOut.close (); serverOut.close (); System.out.println („Pripojenia uzavreté.“); server.close (); System.out.println („Server ukončený.“); }}
Krok 21. Zostavte a spustite
Protokolovanie nám umožnilo zistiť, či bola aplikácia úspešná alebo nie. Očakávaný výkon:
Server spustený. Pripája sa k serveru … Pripojenie bolo nadviazané. Komunikácia je pripravená. Správa odoslaná na server: Hello World Správa prijatá od klienta: Hello World Connections zatvorené. Server ukončený.
V prípade, že váš výstup nie je taký, ako je uvedený vyššie, čo je nepravdepodobné, existuje niekoľko riešení:
-
Ak sa výstup zastaví na linke
Pripojenie nadviazané.
a používajú sa toky objektov, prepláchnite každý
ObjectOutputStream
- bezprostredne po inicializácii, pretože hlavičky z nejakého dôvodu neboli odoslané.
-
Ak sa výstup vytlačí
java.net. BindException: Adresa sa už používa
- zvoľte iné číslo portu, pretože zadané je už použité.
Tipy
- Pripojenie k serveru v inej sieti sa vykonáva pripojením k externej adrese IP zariadenia, na ktorom je spustený server s presmerovaným portom.
- Pripojenie k serveru v rovnakej sieti sa vykonáva buď pripojením k súkromnej adrese IP zariadenia, na ktorom je server spustený, alebo presmerovaním portu a pripojením k externej adrese IP zariadenia.
- Existuje softvér, napríklad Hamachi, ktorý umožňuje pripojenie k serveru v inej sieti bez presmerovania portu, ale vyžaduje inštaláciu softvéru na obe zariadenia.
Príklady
Sieťové aplikácie, ktoré používajú blokovanie vstupu/výstupu, musia používať vlákna. Nasledujúce príklady ukazujú minimalistickú implementáciu servera a klienta pomocou vlákien. Sieťový kód je v zásade rovnaký ako v článku, ibaže niektoré úryvky boli synchronizované, presunuté do vlákien a riešené výnimky.
Server.java
import java.io. IOException; import java.net. InetAddress; import java.net. ServerSocket; import java.net. SocketException; import java.net. UnknownHostException; import java.util. ArrayList; import java.util. Collections; import java.util. List; /*** Trieda {@code Server} predstavuje koncový bod servera v sieti. {@code Server}, keď je viazaný na určitú adresu IP * a port, nadviaže spojenie s klientmi a je schopný s nimi komunikovať alebo ich odpojiť. *
* Táto trieda je bezpečná pre vlákna. * * @version 1.0 * @see Client * @see Connection */ public class Server implementuje spustiteľný {private ServerSocket server; súkromný zoznam
spojenia; vlákno súkromného vlákna; private final Object connectionsLock = nový Object (); /** * Vytvorí {@code Server}, ktorý interaguje s klientmi na zadanom názve hostiteľa a porte so zadanou * požadovanou maximálnou dĺžkou frontu prichádzajúcich klientov. * * @param hostiteľ Adresa hostiteľa, ktorú chcete použiť. * @param port Číslo portu, ktorý sa má použiť. * @param backlog Požadovaná maximálna dĺžka frontu prichádzajúcich klientov. * @throws NetworkException Ak sa pri spustení servera vyskytne chyba. */ public Server (String host, int port, int backlog) hodí NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throw new NetworkException ("Názov hostiteľa sa nepodarilo vyriešiť:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Číslo portu musí byť medzi 0 a 65535 (vrátane):" + port); } catch (IOException e) {throw new NetworkException („Server nebolo možné spustiť.“, e); } connections = Collections.synchronizedList (new ArrayList ()); vlákno = nové vlákno (toto); thread.start (); } /*** Vytvorí {@code server}, ktorý interaguje s klientmi na zadanom názve hostiteľa a porte. * * @param hostiteľ Adresa hostiteľa na väzbu. * @param port Číslo portu na viazanie. * @throws NetworkException Ak sa pri spustení servera vyskytnú chyby. */ public Server (String host, int port) hodí NetworkException {this (host, port, 50); } /*** Počúva, prijíma a registruje prichádzajúce pripojenia od klientov. */ @Override public void run () {while (! Server.isClosed ()) {try {connections.add (new Connection (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Odosiela údaje všetkým registrovaným klientom. * * @param údaje Údaje na odoslanie. * @throws IllegalStateException Ak sa pokúsite o zápis údajov, keď je server offline. * @throws IllegalArgumentException Ak sú údaje na odoslanie nulové. */ public void broadcast (Object data) {if (server.isClosed ()) {throw new IllegalStateException ("Data not sent, server is offline."); } if (data == null) {throw new IllegalArgumentException ("null data"); } synchronizované (connectionsLock) {pre (Connection connection: connections) {try {connection.send (data); System.out.println ("Údaje boli úspešne odoslané klientovi."); } catch (NetworkException e) {e.printStackTrace (); }}}} /*** Pošle správu o odpojení a odpojí zadaného klienta. * * @param pripojenie Klient sa odpojí. * @throws NetworkException Ak sa pri zatváraní pripojenia vyskytne chyba. */ public void disconnect (Connection connection) hodí NetworkException {if (connections.remove (connection)) {connection.close (); }} /*** Odošle všetkým klientom správu o odpojení, odpojí ich a ukončí server. */ public void close () hodí NetworkException {synchronized (connectionsLock) {for (Connection connection: connections) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} connections.clear (); skúste {server.close (); } catch (IOException e) {throw new NetworkException ("Chyba pri zatváraní servera."); } konečne {vlákno.interrupt (); }} /*** Vráti, či je server online. * * @return Pravda, ak je server online. Falošné, inak. */ public boolean isOnline () {return! server.isClosed (); } /*** Vráti množstvo registrovaných klientov. */ public Connection getConnections () {synchronized (connectionsLock) {return connections.toArray (new Connection [connections.size ()]); }}}
Client.java
import java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; /*** Trieda {@code Client} predstavuje koncový bod klienta v sieti. {@code Client}, keď je pripojený k určitému * serveru, bude zaručene schopný komunikovať iba so serverom. To, či údaje dostanú iní klienti *, závisí od implementácie servera. *
* Táto trieda je bezpečná pre vlákna. * * @version 1.0 * @viz Server * @viz Pripojenie */ klient verejnej triedy {pripojenie súkromného pripojenia; /*** Vytvorí {@code Client} pripojeného k serveru na zadanom hostiteľovi a porte. * * @param hostiteľ Adresa hostiteľa na väzbu. * @param port Číslo portu na viazanie. * @throws NetworkException Ak sa pri spustení servera vyskytne chyba. */ public Client (String host, int port) hodí NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Názov hostiteľa sa nepodarilo vyriešiť:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Číslo portu musí byť medzi 0 a 65535 (vrátane):" + port); } catch (IOException e) {throw new NetworkException („Server nebolo možné spustiť.“, e); }} /*** Odošle údaje druhej strane. * * @param údaje Údaje na odoslanie. * @throws NetworkException Ak zápis do výstupného toku zlyhá. * @throws IllegalStateException Ak sa pokúsite o zápis údajov, keď je pripojenie uzavreté. * @throws IllegalArgumentException Ak sú údaje na odoslanie nulové. * @throws UnsupportedOperationException Ak sa pokúšate odoslať nepodporovaný typ údajov. */ public void send (údaje o objektoch) vyvolá NetworkException {connection.send (data); } /*** Odošle správu o odpojení na server a ukončí spojenie so serverom. */ public void close () hodí NetworkException {connection.close (); } /*** Vráti, či je klient pripojený k serveru alebo nie. * * @return True, ak je klient pripojený. Falošné, inak. */ public boolean isOnline () {return connection.isConnected (); } /*** Vráti inštanciu klienta {@link Connection}. */ public Connection getConnection () {spätné pripojenie; }}
Connection.java
import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; /** * Trieda {@code Connection} predstavuje buď pripojenie servera ku klientovi, alebo koncový bod klienta v sieti * {@code Connection} po pripojení si dokáže vymieňať údaje s inou stranou alebo stranami v závislosti od na implementácii servera *. *
* Táto trieda je bezpečná pre vlákna. * * @version 1.0 * @see Server * @see Client */ public class Pripojenie implementuje Spustiteľné {private Socket socket; súkromný DataOutputStream von; súkromný DataInputStream v; vlákno súkromného vlákna; private final Object writeLock = nový Object (); private final Objekt readLock = nový Object (); /*** Vytvára {@code Connection} pomocou streamov určeného {@link Socket}. * * @param socket Zásuvka na načítanie streamov z.*/ public Connection (Socket socket) hodí NetworkException {if (socket == null) {throw new IllegalArgumentException ("null socket"); } this.socket = socket; try {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException ("Could not access output stream.", e); } try {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException ("Could not access input stream.", e); } vlákno = nové vlákno (toto); thread.start (); } /*** Číta správy, keď je spojenie s druhou stranou živé. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; byte bajtov; synchronizované (readLock) {identifier = in.readInt (); int dĺžka = in.readInt (); if (dĺžka> 0) {bajtov = nový bajt [dĺžka]; in.readFully (bajty, 0, bajty.dĺžka); } else {pokračovať; }} switch (identifier) {case Identifier. INTERNAL: String command = new String (bytes); if (command.equals ("disconnect")) {if (! socket.isClosed ()) {System.out.println ("Disconnection packet prijat."); skus {zavri (); } catch (NetworkException e) {return; } } } prestávka; case Identifier. TEXT: System.out.println ("Prijatá správa:" + nový reťazec (bajty)); prestávka; predvolené: System.out.println ("Prijaté boli nerozpoznané údaje."); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} /*** Odošle údaje druhej strane. * * @param údaje Údaje na odoslanie. * @throws NetworkException Ak zápis do výstupného toku zlyhá. * @throws IllegalStateException Ak sa pokúsite o zápis údajov, keď je pripojenie uzavreté. * @throws IllegalArgumentException Ak sú údaje na odoslanie nulové. * @throws UnsupportedOperationException Ak sa pokúšate odoslať nepodporovaný typ údajov. */ public void send (Údaje o objektoch) vyvolá NetworkException {if (socket.isClosed ()) {throw new IllegalStateException („Údaje neboli odoslané, pripojenie je uzavreté.“); } if (data == null) {throw new IllegalArgumentException ("null data"); } identifikátor int; byte bajtov; if (dátová inštancia reťazca) {identifier = Identifier. TEXT; bajty = ((Reťazec) údaje).getBytes (); } else {throw new UnsupportedOperationException ("Unsupported data type:" + data.getClass ()); } skúste {synchronizované (writeLock) {out.writeInt (identifikátor); out.writeInt (bajty.dĺžka); out.write (bajty); out.flush (); }} catch (IOException e) {throw new NetworkException ("Data could not be sent.", e); }} /*** Odošle druhej strane správu o odpojení a uzavrie s ňou spojenie. */ public void close () hodí NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Pripojenie je už uzavreté."); } skúste {byte message = "odpojiť".getBytes (); synchronizované (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.write (správa); out.flush (); }} catch (IOException e) {System.out.println ("Správu o odpojení nebolo možné odoslať."); } skúste {synchronizované (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException („Chyba pri zatváraní pripojenia.“, e); } konečne {vlákno.interrupt (); }} /*** Vráti, či je alebo nie je nadviazané spojenie s druhou stranou. * * @return Pravda, ak je pripojenie živé. Falošné, inak. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifier.java
/** * Trieda {@code Identifier} obsahuje konštanty, ktoré používa {@link Connection} na serializáciu a deserializáciu údajov * odoslaných cez sieť. * * @version 1.0 * @viz Pripojenie * / verejný identifikátor konečnej triedy { / ** * Identifikátor pre interné správy. */ public static final int INTERNAL = 1; /*** Identifikátor pre textové správy. */ public static final int TEXT = 2; }
NetworkException.java
/*** Trieda {@code NetworkException} označuje chybu súvisiacu so sieťou. * / public class NetworkException extends Exception { / *** Constructs a {@code NetworkException} with {@code null} as its message. * / public NetworkException () {} / *** Vytvorí {@code NetworkException} so zadanou správou. * * @param správa Správa popisujúca chybu. */ public NetworkException (String message) {super (message); } /*** Vytvorí {@code NetworkException} so zadanou správou a príčinou. * * @param správa Správa popisujúca chybu. * @param príčina Príčina chyby. */ public NetworkException (reťazcová správa, vyvolávacia príčina) {super (správa, príčina); } /*** Vytvorí {@code NetworkException} so zadanou príčinou. * * @param príčina Príčina chyby. */ public NetworkException (vyvolávacia príčina) {super (príčina); }}
UsageExample.java
/*** Trieda {@code UsageExample} ukazuje použitie {@link Server} a {@link Client}. Tento príklad používa * {@link Thread#sleep (long)} na zaistenie vykonania každého segmentu, pretože rýchle spustenie a zatvorenie spôsobuje, že niektoré * segmenty sa nespúšťajú. * * @version 1.0 * @viz Server * @viz Klient */ verejná trieda UsageExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; Server server = nový server (hostiteľ, port); Klient klienta = nový klient (hostiteľ, port); Thread.sleep (100L); client.send („Dobrý deň.“); server.broadcast („Hej, chlapče!“); Thread.sleep (100L); server.disconnect (server.getConnections () [0]); // alebo client.close () na odpojenie od server-server-server.close (); }}