Pisanje kode, ki se izvaja na določeni napravi, je zelo zadovoljivo. Toda pisanje kode, ki se izvaja na več napravah, ki med seboj komunicirajo, preprosto potrjuje življenje. Ta članek vas bo naučil, kako povezati in izmenjati sporočila po omrežju z uporabo protokola za nadzor prenosa (TCP).
V tem članku boste nastavili aplikacijo, ki bo vaš računalnik povezala sama s seboj in v bistvu zmešala - pogovarjajte se sami s seboj. Spoznali boste tudi razliko med dvema najpogosteje uporabljanima tokovoma za povezovanje v omrežje Java in kako delujeta.
Tokovi podatkov in objektov
Preden se poglobimo v kodo, je treba razlikovati med dvema tokoma, uporabljenimi v članku.
Podatkovni tokovi
Podatkovni tokovi obdelujejo primitivne vrste podatkov in nize. Podatke, poslane prek podatkovnih tokov, je treba ročno serijalizirati in deserializirati, kar otežuje prenos kompleksnih podatkov. Podatkovni tokovi pa lahko komunicirajo s strežniki in odjemalci, napisanimi v drugih jezikih kot v Javi. Surovi tokovi so v tem pogledu podobni tokovom podatkov, vendar podatkovni tokovi zagotavljajo, da so podatki oblikovani na način, neodvisen od platforme, kar je koristno, saj bosta obe strani lahko brali poslane podatke.
Objektni tokovi
Objektni tokovi obdelujejo primitivne vrste podatkov in objekte, ki jih implementirajo
Serializable
vmesnik. Podatki, poslani prek tokov objektov, so samodejno serijalizirani in deserializirani, kar olajša prenos kompleksnih podatkov. Predmeti objektov pa lahko komunicirajo samo s strežniki in odjemalci, napisanimi v Javi. Prav tako,
ObjectOutputStream
ob inicializaciji pošlje glavo v
InputStream
druge strani, ki ob inicializaciji blokira izvajanje, dokler ne prejme glave.
Koraki
Korak 1. Ustvarite razred
Ustvarite razred in ga poimenujte, kakor želite. V tem članku bo imenovan
NetworkAppExample
javni razred NetworkAppExample {}
Korak 2. Ustvarite glavno metodo
Ustvarite glavno metodo in izjavite, da bi lahko povzročila izjeme
Izjema
tip in kateri koli njegov podrazred - vse izjeme. To velja za slabo prakso, vendar je sprejemljivo za primere barebone.
javni razred NetworkAppExample {public static void main (String args) throws Exception {}}
Korak 3. Navedite naslov strežnika
Ta primer bo uporabil lokalni naslov gostitelja in poljubno številko vrat. Številka vrat mora biti v območju od 0 do 65535 (vključno). Številke vrat, ki se jim je treba izogniti, segajo od 0 do 1023 (vključno), ker so rezervirana sistemska vrata.
javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; }}
Korak 4. Ustvarite strežnik
Strežnik je vezan na naslov in vrata ter posluša dohodne povezave. V Javi,
ServerSocket
predstavlja končno točko na strani strežnika in njena funkcija je sprejemanje novih povezav.
ServerSocket
nima tokov za branje in pošiljanje podatkov, ker ne predstavlja povezave med strežnikom in odjemalcem.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); }}
Korak 5. Začetek strežnika dnevnika
Za namene beleženja na konzolo natisnite, da je strežnik zagnan.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); }}
Korak 6. Ustvarite odjemalca
Odjemalec je vezan na naslov in vrata strežnika ter po vzpostavitvi povezave posluša pakete (sporočila). V Javi,
Vtičnica
predstavlja bodisi končno točko na strani odjemalca, ki je povezana s strežnikom, ali povezavo (od strežnika) do odjemalca in se uporablja za komunikacijo s stranko na drugem koncu.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); }}
Korak 7. Zabeležite poskus povezave
Za namene beleženja na konzolo natisnite, da je bila vzpostavljena povezava.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); }}
Korak 8. Vzpostavite povezavo
Odjemalci se ne bodo nikoli povezali, če strežnik ne posluša in ne sprejme, z drugimi besedami, vzpostavi povezav. V Javi se povezave vzpostavijo z uporabo
sprejmi ()
metoda
ServerSocket
razred. Metoda bo blokirala izvajanje, dokler se odjemalec ne poveže.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); }}
Korak 9. Zapišite vzpostavljeno povezavo
Za namene beleženja na konzolo natisnite povezavo med strežnikom in odjemalcem.
uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); }}
Korak 10. Pripravite komunikacijske tokove
Komunikacija poteka prek tokov in v tej aplikaciji je treba surove tokove (povezave s) strežnika (do odjemalca) in odjemalca povezati v tok podatkov ali objektov. Ne pozabite, da morata obe strani uporabljati isto vrsto toka.
-
Tokovi podatkov
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); DataOutputStream clientOut = nov DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nov DataInputStream (client.getInputStream ()); DataOutputStream serverOut = nov DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = nov DataInputStream (connection.getInputStream ()); }}
-
Objektni tokovi
Ko se uporablja več tokov objektov, je treba vhodne tokove inicializirati v istem vrstnem redu kot izhodni tokovi, ker
ObjectOutputStream
pošlje glavo drugi osebi in
ObjectInputStream
blokira izvajanje, dokler ne prebere glave.
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); ObjectOutputStream clientOut = nov ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nov ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nov ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nov ObjectInputStream (connection.getInputStream ()); }}
Naročilo, kot je navedeno v zgornji kodi, si je morda lažje zapomniti - najprej inicializirajte izhodne tokove, nato vhodne tokove v istem vrstnem redu. Vendar je drugo naročilo za inicializacijo tokov objektov naslednje:
ObjectOutputStream clientOut = nov ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = nov ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = nov ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nov ObjectInputStream (client.getInputStream ());
Korak 11. Zapišite, da je komunikacija pripravljena
Za namene beleženja na konzolo natisnite, da je komunikacija pripravljena.
// koda izpuščena uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); // koda izpuščena System.out.println ("Komunikacija je pripravljena."); }}
Korak 12. Ustvarite sporočilo
V tej vlogi
Pozdravljen, svet
besedilo bo poslano na strežnik bodisi kot
bajt
ali
Vrvica
. Razglasite spremenljivko vrste, ki je odvisna od uporabljenega toka. Uporaba
bajt
za podatkovne tokove in
Vrvica
za tokove objektov.
-
Tokovi podatkov
Z uporabo podatkovnih tokov se serijalizacija izvede s pretvorbo objektov v primitivne vrste podatkov ali a
Vrvica
. V tem primeru,
Vrvica
se pretvori v
bajt
namesto pisne uporabe
writeBytes ()
metoda, ki prikazuje, kako bi to storili z drugimi predmeti, kot so slike ali druge datoteke.
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); byte messageOut = "Pozdravljeni svet".getBytes (); }}
-
Objektni tokovi
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); String messageOut = "Pozdravljeni svet"; }}
Korak 13. Pošljite sporočilo
Zapišite podatke v izhodni tok in izperite tok, da zagotovite, da so podatki v celoti zapisani.
-
Tokovi podatkov
Najprej je treba poslati dolžino sporočila, tako da druga oseba ve, koliko bajtov mora prebrati. Ko je dolžina poslana kot primitivna cela vrsta, se lahko pošljejo bajti.
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); byte messageOut = "Pozdravljeni svet".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektni tokovi
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); String messageOut = "Pozdravljeni svet"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Korak 14. Dnevnik poslanega sporočila
Za namene beleženja na konzolo natisnite to sporočilo.
-
Tokovi podatkov
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik zagnan."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); byte messageOut = "Pozdravljeni svet".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + nov niz (messageOut)); }}
-
Objektni tokovi
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); String messageOut = "Pozdravljeni svet"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + messageOut); }}
Korak 15. Preberite sporočilo
Preberite podatke iz vhodnega toka in jih pretvorite. Ker natančno poznamo vrsto poslanih podatkov, bomo ustvarili datoteko
Vrvica
od
bajt
ali oddano
Objekt
do
Vrvica
brez preverjanja, odvisno od uporabljenega toka.
-
Tokovi podatkov
Ker je bila dolžina najprej poslana, nato pa bajti, je treba branje opraviti v istem vrstnem redu. Če je dolžina nič, ni ničesar za brati. Objekt je deserializiran, ko se bajti pretvorijo nazaj v primerek, v tem primeru, datoteke
Vrvica
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); byte messageOut = "Pozdravljeni svet".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + nov niz (messageOut)); int length = serverIn.readInt (); if (dolžina> 0) {byte messageIn = nov bajt [dolžina]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektni tokovi
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); String messageOut = "Pozdravljeni svet"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + messageOut); Niz messageIn = (Niz) serverIn.readObject (); }}
Korak 16. Dnevnik prebranega sporočila
Za namene beleženja na konzolo natisnite prejeto sporočilo in natisnite njegovo vsebino.
-
Tokovi podatkov
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); byte messageOut = "Pozdravljeni svet".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + nov niz (messageOut)); int length = serverIn.readInt (); if (dolžina> 0) {byte messageIn = nov bajt [dolžina]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Sporočilo prejeto od odjemalca:" + nov niz (messageIn)); }}}
-
Objektni tokovi
uvoz java.io. ObjectInputStream; uvoz java.io. ObjectOutputStream; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); 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 ("Komunikacija je pripravljena."); String messageOut = "Pozdravljeni svet"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Sporočilo poslano strežniku:" + messageOut); Niz messageIn = (Niz) serverIn.readObject (); System.out.println ("Sporočilo prejeto od odjemalca:" + messageIn); }}
Korak 17. Prekinite povezave
Povezava se prekine, ko ena stran zapre svoje tokove. V Javi se z zapiranjem izhodnega toka zaprejo tudi povezana vtičnica in vhodni tok. Ko stranka na drugi strani ugotovi, da je povezava prekinjena, mora zapreti tudi svoj izhodni tok, da prepreči uhajanje pomnilnika.
// koda izpuščena uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); // koda izpuščena System.out.println ("Komunikacija je pripravljena."); // koda izpuščena clientOut.close (); serverOut.close (); }}
Korak 18. Prekinitev dnevnika
Za namene beleženja so bile povezave tiskanja na konzolo prekinjene.
// koda izpuščena uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); // koda izpuščena System.out.println ("Komunikacija je pripravljena."); // koda izpuščena clientOut.close (); serverOut.close (); System.out.println ("Povezave zaprte."); }}
Korak 19. Končajte strežnik
Povezave so prekinjene, strežnik pa še vedno deluje. As
ServerSocket
ni povezan z nobenim tokom, ga je treba izrecno zapreti s klicem
zapri ()
metoda.
// koda izpuščena uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); // koda izpuščena System.out.println ("Komunikacija je pripravljena."); // koda izpuščena clientOut.close (); serverOut.close (); System.out.println ("Povezave zaprte."); server.close (); }}
Korak 20. Zaključitev strežnika dnevnika
Za namene beleženja je bilo tiskanje na strežnik ukazne mize prekinjeno.
// koda izpuščena uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. Socket; javni razred NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket strežnik = nov ServerSocket (vrata, 50, InetAddress.getByName (gostitelj)); System.out.println ("Strežnik se je zagnal."); Odjemalec vtičnice = nova vtičnica (gostitelj, vrata); System.out.println ("Povezovanje s strežnikom …"); Socket connection = server.accept (); System.out.println ("Povezava vzpostavljena."); // koda izpuščena System.out.println ("Komunikacija je pripravljena."); // koda izpuščena clientOut.close (); serverOut.close (); System.out.println ("Povezave zaprte."); server.close (); System.out.println ("Strežnik prekinjen."); }}
Korak 21. Prevedite in zaženite
Z beleženjem smo ugotovili, ali je bila aplikacija uspešna ali ne. Pričakovana proizvodnja:
Strežnik se je zagnal. Povezovanje s strežnikom … Povezava vzpostavljena. Komunikacija je pripravljena. Sporočilo poslano strežniku: Hello World Sporočilo prejeto od odjemalca: Hello World Connections closed. Strežnik prekinjen.
Če vaš rezultat ni podoben zgornjemu, kar se verjetno ne bo zgodilo, obstaja nekaj rešitev:
-
Če se izhod ustavi na liniji
Povezava vzpostavljena.
in se uporabljajo tokovi predmetov, vsakega sperite
ObjectOutputStream
- takoj po inicializaciji, ker glave iz nekega razloga niso bile poslane.
-
Če se izpis natisne
java.net. BindException: Naslov je že v uporabi
- izberite drugo številko vrat, ker je navedena že uporabljena.
Nasveti
- Povezovanje s strežnikom v drugem omrežju se izvede tako, da se povežete z zunanjim naslovom IP naprave, ki uporablja strežnik, ki ima posredovana vrata.
- Povezovanje s strežnikom v istem omrežju se izvede tako, da se povežete z zasebnim naslovom IP naprave, ki uporablja strežnik, ali posredujete vrata in se povežete z zunanjim naslovom IP naprave.
- Obstaja programska oprema, na primer Hamachi, ki omogoča povezavo s strežnikom v drugem omrežju brez posredovanja vrat, vendar zahteva namestitev programske opreme na obe napravi.
Primeri
Mrežne aplikacije, ki uporabljajo blokiranje vhoda/izhoda, morajo uporabljati niti. Naslednji primeri prikazujejo minimalistično izvedbo strežnika in odjemalca z nitmi. Omrežna koda je v bistvu enaka kot v članku, le da so bili nekateri izrezki sinhronizirani, premaknjeni v niti in obravnavane izjeme.
Server.java
uvoz java.io. IOException; uvoz java.net. InetAddress; uvoz java.net. ServerSocket; import java.net. SocketException; import java.net. UnknownHostException; uvoz java.util. ArrayList; import java.util. Collections; uvoz java.util. List; /*** Razred {@code Server} predstavlja končno točko strežnika v omrežju. {@code Server}, ko je enkrat povezan z določenim naslovom in vrati IP *, vzpostavi povezave s odjemalci in lahko komunicira z njimi ali jih prekine. *
* Ta razred je varen za nit. * * @version 1.0 * @see Client * @see Connection */ javni razred Strežnik implementira Runnable {private ServerSocket server; zasebni seznam
povezave; zasebna nitna nit; private final Objects connectionsLock = nov Objekt (); /** * Ustvari {@code Server}, ki komunicira s odjemalci na določenem imenu gostitelja in vratih z določeno * zahtevano največjo dolžino čakalne vrste dohodnih odjemalcev. * * @param gostiteljica Naslov gostitelja za uporabo. * @param port Številka vrat za uporabo. * @param backlog Zahtevana največja dolžina čakalne vrste dohodnih strank. * @throws NetworkException Če pride do napake med zagonom strežnika. */ javni strežnik (gostitelj nizov, vrata int, int zaostanek) vrže NetworkException {poskusite {server = new ServerSocket (vrata, zaostanek, InetAddress.getByName (gostitelj)); } catch (UnknownHostException e) {throw new NetworkException ("Ime gostitelja ni bilo mogoče razrešiti:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Številka vrat mora biti med 0 in 65535 (vključno):" + vrata); } catch (IOException e) {throw new NetworkException ("Strežnika ni bilo mogoče zagnati.", e); } povezave = Collections.synchronizedList (nov ArrayList ()); nit = nova nit (to); thread.start (); } /*** Ustvari {@code Server}, ki komunicira s odjemalci na določenem imenu gostitelja in vratih. * * @param host Gostiteljski naslov za vezavo. * @param port Število vrat za vezavo. * @throws NetworkException Če pri zagonu strežnika pride do napak. */ javni strežnik (niz gostiteljev, int vrata) vrže NetworkException {this (gostitelj, vrata, 50); } /*** Sluša, sprejema in registrira dohodne povezave strank. */ @Override public void run () {while (! Server.isClosed ()) {try {connections.add (nova povezava (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Pošlje podatke vsem registriranim odjemalcem. * * @param podatki Podatki za pošiljanje. * @throws IllegalStateException Če poskušate zapisati podatke, ko strežnik ni povezan. * @throws IllegalArgumentException Če so podatki za pošiljanje ničelni. */ javna oddaja praznine (podatki o objektu) {if (server.isClosed ()) {vrzi novo IllegalStateException ("Podatki niso poslani, strežnik je brez povezave."); } if (data == null) {throw new IllegalArgumentException ("ničelni podatki"); } sinhronizirano (connectionsLock) {za (Povezava povezave: povezave) {poskusite {connection.send (data); System.out.println ("Podatki uspešno poslani odjemalcu."); } catch (NetworkException e) {e.printStackTrace (); }}}} /*** Pošlje sporočilo o prekinitvi povezave in odklopi določenega odjemalca. * * @param connection Odjemalec za prekinitev povezave. * @throws NetworkException Če pride do napake med prekinitvijo povezave. */ public void disconnect (Povezava povezave) vrže NetworkException {if (connections.remove (connection)) {connection.close (); }} /*** Pošlje sporočilo o prekinitvi povezave vsem odjemalcem, jih prekine in prekine strežnik. */ public void close () vrže NetworkException {synchronized (connectionsLock) {for (Povezava povezave: povezave) {poskusite {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} links.clear (); poskusite {server.close (); } catch (IOException e) {throw new NetworkException ("Napaka pri zapiranju strežnika."); } končno {thread.interrupt (); }} /*** Vrne, ali je strežnik povezan. * * @return True, če je strežnik na spletu. Napačno, drugače. */ javno logično isOnline () {return! server.isClosed (); } /*** Vrne polje registriranih odjemalcev. */ public Connection getConnections () {synchronized (connectionsLock) {return connections.toArray (new Connection [connections.size ()]); }}}
Client.java
uvoz java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; /*** Razred {@code Client} predstavlja odjemalčevo končno točko v omrežju. {@code Client}, ko bo enkrat povezan z določenim * strežnikom, bo zagotovil le komunikacijo s strežnikom. Ali bodo druge stranke prejele podatke *, je odvisno od izvedbe strežnika. *
* Ta razred je varen za nit. * * @version 1.0 * @see Server * @see Connection */ javni razred Client {private Connection connection; /*** Ustvari odjemalca {@code}, povezanega s strežnikom na določenem gostitelju in vratih. * * @param gostiteljica Naslov gostitelja za vezavo. * @param port Število vrat za vezavo. * @throws NetworkException Če pride do napake med zagonom strežnika. */ javni odjemalec (Niz gostitelja, int vrata) vrže NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Ime gostitelja ni bilo mogoče razrešiti:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Številka vrat mora biti med 0 in 65535 (vključno):" + vrata); } catch (IOException e) {throw new NetworkException ("Strežnika ni bilo mogoče zagnati.", e); }} /*** Pošlje podatke drugi osebi. * * @param podatki Podatki za pošiljanje. * @throws NetworkException Če pisanje v izhodni tok ne uspe. * @throws IllegalStateException Če poskusite zapisati podatke, ko je povezava prekinjena. * @throws IllegalArgumentException Če so podatki za pošiljanje ničelni. * @throws UnsupportedOperationException Če poskušate poslati nepodprto vrsto podatkov. */ public void send (Object data) vrže NetworkException {connection.send (data); } /*** Pošlje sporočilo o prekinitvi povezave s strežnikom in zapre povezavo s strežnikom. */ public void close () vrže NetworkException {connection.close (); } /*** Vrne, ali je odjemalec povezan s strežnikom. * * @return True, če je odjemalec povezan. Napačno, drugače. */ javno logično isOnline () {vrni povezavo.isConnected (); } /*** Vrne primerek odjemalca {@link Connection}. */ javna povezava getConnection () {povratna povezava; }}
Connection.java
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.io. IOException; import java.net. Socket; import java.net. SocketException; /** * Razred {@code Connection} predstavlja bodisi povezavo od strežnika do odjemalca bodisi odjemalsko končno točko v omrežju * {@code Connection}, ko je enkrat povezan, lahko izmenjuje podatke z drugimi strankami, odvisno od na strežniku * izvedba. *
* Ta razred je varen za nit. * * @version 1.0 * @see Server * @see Client */ javni razred Povezava izvaja Runnable {private Socket socket; zasebni DataOutputStream out; zasebni DataInputStream v; zasebna nitna nit; zasebni končni predmet writeLock = nov predmet (); zasebni končni predmet readLock = nov predmet (); /*** Ustvari {@code Connection} z uporabo tokov določene {@link vtičnice}. * * @param vtičnica Vtičnica za prenos tokov.*/ javna povezava (vtičnica vtičnice) vrže NetworkException {if (socket == null) {vrže novo IllegalArgumentException ("ničelna vtičnica"); } this.socket = vtičnica; poskusite {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException ("Dostop do izhodnega toka ni mogoč.", e); } poskusite {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException ("Dostop do vhodnega toka ni mogoč.", e); } nit = nova nit (to); thread.start (); } /*** Bere sporočila, medtem ko je povezava z drugo stranjo živa. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; byte bajti; sinhronizirano (readLock) {identifikator = in.readInt (); int length = in.readInt (); if (dolžina> 0) {bajtov = nov bajt [dolžina]; in.readFully (bajti, 0, dolžina bajtov); } else {nadaljevanje; }} stikalo (identifikator) {Identifikator primera. INTERNAL: Ukaz niza = nov niz (bajti); if (command.equals ("odklopi")) {if (! socket.isClosed ()) {System.out.println ("Prejet paket prekinitve."); poskusi {close (); } catch (NetworkException e) {return; }}} prelom; identifikator velike črke. TEXT: System.out.println ("Prejeto sporočilo:" + nov niz (bajti)); prekiniti; privzeto: System.out.println ("Prejeti neprepoznani podatki."); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} /*** Pošlje podatke drugi osebi. * * @param podatki Podatki za pošiljanje. * @throws NetworkException Če pisanje v izhodni tok ne uspe. * @throws IllegalStateException Če poskusite zapisati podatke, ko je povezava prekinjena. * @throws IllegalArgumentException Če so podatki za pošiljanje ničelni. * @throws UnsupportedOperationException Če poskušate poslati nepodprto vrsto podatkov. */ public void send (Object data) vrže NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Podatki niso poslani, povezava je zaprta."); } if (data == null) {throw new IllegalArgumentException ("ničelni podatki"); } int identifikator; byte bajti; if (podatkovni primerek niza) {identifier = Identifier. TEXT; bajti = ((String) podatki).getBytes (); } else {throw new UnsupportedOperationException ("Nepodprta vrsta podatkov:" + data.getClass ()); } poskusite {synchronized (writeLock) {out.writeInt (identifikator); out.writeInt (bytes.length); out.write (bajti); out.flush (); }} catch (IOException e) {throw new NetworkException ("Podatkov ni bilo mogoče poslati.", e); }} /*** Pošlje sporočilo o prekinitvi povezave in prekine povezavo z drugo stranjo. */ public void close () vrže NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Povezava je že zaprta."); } poskusite {byte message = "prekinite povezavo".getBytes (); sinhronizirano (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.write (sporočilo); out.flush (); }} catch (IOException e) {System.out.println ("Sporočila o prekinitvi povezave ni bilo mogoče poslati."); } poskusite {synchronized (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Napaka pri prekinitvi povezave.", e); } končno {thread.interrupt (); }} /*** Vrne, ali je povezava z drugo stranjo živa ali ne. * * @return True, če je povezava živa. Napačno, drugače. */ javno logično isConnected () {return! socket.isClosed (); }}
Identifier.java
/** * Razred {@code Identifier} vsebuje konstante, ki jih uporablja {@link Connection} za serijsko in deserializacijo podatkov *, poslanih po omrežju. * * @version 1.0 * @see Connection * / public final class Identifier { / ** * Identifikator za interna sporočila. */ javni statični končni int INTERNAL = 1; /*** Identifikator za besedilna sporočila. */ javni statični končni int TEXT = 2; }
NetworkException.java
/*** Razred {@code NetworkException} označuje napako, povezano z omrežjem. * / javni razred NetworkException razširja Exception { / *** Ustvari {@code NetworkException} s sporočilom {@code null}. * / public NetworkException () {} / *** Ustvari {@code NetworkException} z navedenim sporočilom. * * @param sporočilo Sporočilo za opis napake. */ public NetworkException (String message) {super (message); } /*** Ustvari {@code NetworkException} z navedenim sporočilom in vzrokom. * * @param sporočilo Sporočilo za opis napake. * @param vzrok Vzrok za napako. */ public NetworkException (sporočilo niza, vzrok za zavrnitev) {super (sporočilo, vzrok); } /*** Ustvari {@code NetworkException} z navedenim vzrokom. * * @param vzrok Vzrok za napako. */ public NetworkException (Vnosljiv vzrok) {super (vzrok); }}
UsageExample.java
/*** Razred {@code UsageExample} prikazuje uporabo {@link Server} in {@link Client}. Ta primer uporablja * {@link Thread#sleep (long)} za zagotovitev izvajanja vseh segmentov, ker hiter zagon in zapiranje povzroči, da se nekateri * segmenti ne izvedejo. * * @version 1.0 * @see Server * @see Client */ javni razred UsageExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; Strežniški strežnik = nov strežnik (gostitelj, vrata); Odjemalec odjemalca = nov odjemalec (gostitelj, vrata); Thread.sleep (100L); client.send ("Pozdravljeni."); server.broadcast ("Hej, fant!"); Thread.sleep (100L); server.disconnect (server.getConnections () [0]); // ali client.close () za prekinitev povezave s strežnikom na strani odjemalca.close (); }}