Pisanje koda koji se izvršava na određenom uređaju vrlo je zadovoljavajući. No, pisanje koda koji se izvršava na nekoliko uređaja koji međusobno komuniciraju jednostavno potvrđuje život. Ovaj članak će vas naučiti kako se povezati i razmjenjivati poruke putem mreže pomoću protokola za upravljanje prijenosom (TCP).
U ovom ćete članku postaviti aplikaciju koja će vaše računalo povezati sa samim sobom i, u biti, izluditi ga - razgovarajte sami sa sobom. Također ćete naučiti razliku između dva najčešće korištena toka za umrežavanje u Javi i kako oni funkcioniraju.
Tokovi podataka i objekata
Prije ulaska u kôd, potrebno je razlikovati razliku između dvaju tokova koji se koriste u članku.
Prijenos podataka
Tokovi podataka obrađuju primitivne vrste podataka i nizove. Podatke poslane putem podatkovnih tokova potrebno je ručno serijalizirati i deserijalizirati, što otežava prijenos složenih podataka. No, tokovi podataka mogu komunicirati sa poslužiteljima i klijentima napisanim na drugim jezicima osim Jave. Sirovi tokovi slični su tokovima podataka u tom aspektu, ali tokovi podataka osiguravaju da su podaci formatirani na način neovisan o platformi, što je korisno jer će obje strane moći čitati poslane podatke.
Strujanje objekata
Tokovi objekata obrađuju primitivne vrste podataka i objekte koje implementiraju
Serializable
sučelje. Podaci poslani putem tokova objekata automatski se serijaliziraju i deserijaliziraju što olakšava prijenos složenih podataka. No, tokovi objekata mogu komunicirati samo sa poslužiteljima i klijentima napisanim na Javi. Također,
ObjectOutputStream
nakon inicijalizacije, šalje zaglavlje u
Ulazni tok
druge strane koja nakon inicijalizacije blokira izvršavanje dok se zaglavlje ne primi.
Koraci
Korak 1. Stvorite klasu
Napravite klasu i dajte joj ime kako želite. U ovom će članku biti imenovan
Primjer mrežne aplikacije
javni razred NetworkAppExample {}
Korak 2. Izradite glavnu metodu
Izradite glavnu metodu i deklarirajte da bi mogla izazvati iznimke
Izuzetak
tip i bilo koju njegovu podklasu - sve iznimke. To se smatra lošom praksom, ali je prihvatljivo za barebone primjere.
javna klasa NetworkAppExample {public static void main (String args) throws Exception {}}
Korak 3. Navedite adresu poslužitelja
Ovaj primjer će koristiti lokalnu adresu hosta i proizvoljan broj porta. Broj priključka mora biti u rasponu od 0 do 65535 (uključujući). Međutim, brojevi portova koje treba izbjegavati kreću se od 0 do 1023 (uključujući) jer su rezervirani portovi sustava.
javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; }}
Korak 4. Izradite poslužitelj
Poslužitelj je vezan za adresu i port i osluškuje dolazne veze. Na Javi,
ServerSocket
predstavlja krajnju točku na poslužitelju i njezina je funkcija prihvaćanje novih veza.
ServerSocket
nema streamove za čitanje i slanje podataka jer ne predstavlja vezu između poslužitelja i klijenta.
uvoz java.net. InetAddress; import java.net. ServerSocket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); }}
Korak 5. Početak poslužitelja dnevnika
Za potrebe bilježenja ispišite na konzolu da je poslužitelj pokrenut.
uvoz java.net. InetAddress; import java.net. ServerSocket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); }}
Korak 6. Kreirajte klijenta
Klijent je vezan za adresu i port poslužitelja te sluša pakete (poruke) nakon uspostave veze. Na Javi,
Utičnica
predstavlja ili krajnju točku na strani klijenta spojenu na poslužitelj ili vezu (sa poslužitelja) na klijenta i koristi se za komunikaciju sa stranom na drugom kraju.
uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); }}
Korak 7. Zabilježite pokušaj povezivanja
Za potrebe bilježenja ispišite na konzolu pokušaj povezivanja.
uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); }}
Korak 8. Uspostavite vezu
Klijenti se nikada neće povezati ako poslužitelj ne sluša i ne prihvaća, drugim riječima, uspostavlja veze. U Javi se veze uspostavljaju pomoću
prihvatiti()
metoda
ServerSocket
razred. Metoda će blokirati izvršavanje sve dok se klijent ne poveže.
uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); }}
Korak 9. Zabilježite uspostavljenu vezu
Za potrebe bilježenja ispišite na konzolu da je veza između poslužitelja i klijenta uspostavljena.
uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); }}
Korak 10. Pripremite komunikacijske tokove
Komunikacija se odvija putem tokova, a u ovoj aplikaciji sirovi tokovi (povezivanje s) poslužitelja (s klijentom) i klijenta moraju biti povezani lancima na podatkovne ili objektne tokove. Upamtite, obje strane moraju koristiti istu vrstu streama.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); }}
-
Objektni tokovi
Kad se koristi više tijekova objekata, ulazni se tokovi moraju inicijalizirati istim redoslijedom kao izlazni tokovi jer
ObjectOutputStream
šalje zaglavlje drugoj strani i
ObjectInputStream
blokira izvršavanje sve dok ne pročita zaglavlje.
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); }}
Redoslijed naveden u gore navedenom kodu mogao bi biti lakše zapamtiti - prvo inicijalizirajte izlazne tokove, a zatim ulazne tokove istim redoslijedom. Međutim, drugi redoslijed za inicijalizaciju tokova objekata je sljedeći:
ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ());
Korak 11. Zapišite da je komunikacija spremna
Za potrebe bilježenja ispišite na konzolu da je komunikacija spremna.
// kôd izostavljen import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); // kôd izostavljen System.out.println ("Komunikacija je spremna."); }}
Korak 12. Kreirajte poruku
U ovoj aplikaciji,
Pozdrav svijete
tekst će biti poslan na poslužitelj ili kao
bajt
ili
Niz
. Deklarirajte varijablu tipa koja ovisi o korištenom toku. Koristiti
bajt
za tokove podataka i
Niz
za strujanje objekata.
-
Tokovi podataka
Korištenjem tokova podataka, serijalizacija se vrši pretvaranjem objekata u primitivne tipove podataka ili a
Niz
. U ovom slučaju,
Niz
pretvara se u
bajt
umjesto pisanog korištenja
writeBytes ()
metoda koja pokazuje kako bi se to učinilo s drugim objektima, poput slika ili drugih datoteka.
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); byte messageOut = "Zdravo Svijete".getBytes (); }}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); String messageOut = "Zdravo Svijete"; }}
Korak 13. Pošaljite poruku
Zapišite podatke u izlazni tok i isperite tok kako biste bili sigurni da su podaci u potpunosti zapisani.
-
Tokovi podataka
Prvo je potrebno poslati duljinu poruke kako bi druga strana znala koliko bajtova treba pročitati. Nakon što se duljina pošalje kao primitivni cijeli broj, mogu se poslati bajtovi.
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); byte messageOut = "Zdravo Svijete".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); String messageOut = "Zdravo Svijete"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Korak 14. Zabilježite poslanu poruku
Za potrebe bilježenja ispišite na konzolu poruku koja je poslana.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); byte messageOut = "Zdravo Svijete".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + novi niz (messageOut)); }}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); String messageOut = "Zdravo Svijete"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + messageOut); }}
Korak 15. Pročitajte poruku
Očitajte podatke iz ulaznog toka i pretvorite ih. Budući da točno znamo vrstu poslanih podataka, stvorit ćemo ili
Niz
iz
bajt
ili lijevano
Objekt
do
Niz
bez provjere, ovisno o korištenom toku.
-
Tokovi podataka
Kako je prvo poslana duljina, a kasnije bajtovi, čitanje se mora obaviti istim redoslijedom. U slučaju da je duljina nula, nema se što čitati. Objekt se deserijalizira kada se bajtovi pretvore natrag u instancu, u ovom slučaju, datoteke
Niz
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); byte messageOut = "Zdravo Svijete".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + novi niz (messageOut)); int length = serverIn.readInt (); if (length> 0) {byte messageIn = novi bajt [dužina]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); String messageOut = "Zdravo Svijete"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + messageOut); Niz messageIn = (Niz) serverIn.readObject (); }}
Korak 16. Zabilježite pročitanu poruku
Za potrebe bilježenja ispišite na konzolu tu poruku i primite njezin sadržaj.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); DataOutputStream clientOut = novi DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = novi DataInputStream (client.getInputStream ()); DataOutputStream serverOut = novi DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = novi DataInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); byte messageOut = "Zdravo Svijete".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + novi niz (messageOut)); int length = serverIn.readInt (); if (length> 0) {byte messageIn = novi bajt [dužina]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Poruka primljena od klijenta:" + novi niz (messageIn)); }}}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); ObjectOutputStream clientOut = novi ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = novi ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = novi ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = novi ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikacija je spremna."); String messageOut = "Zdravo Svijete"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana poslužitelju:" + messageOut); Niz messageIn = (Niz) serverIn.readObject (); System.out.println ("Poruka primljena od klijenta:" + messageIn); }}
Korak 17. Prekinite veze
Veza se prekida kad jedna strana zatvori svoje tokove. U Javi se zatvaranjem izlaznog toka zatvaraju i pridružena utičnica i ulazni tok. Nakon što strana s druge strane sazna da je veza prekinuta, mora zatvoriti i svoj izlazni tok kako bi spriječila curenje memorije.
// kôd izostavljen import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); // kôd izostavljen System.out.println ("Komunikacija je spremna."); // kôd izostavljen clientOut.close (); serverOut.close (); }}
Korak 18. Isključivanje dnevnika
Radi bilježenja, veze s ispisom na konzolu su prekinute.
// kôd izostavljen import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); // kôd izostavljen System.out.println ("Komunikacija je spremna."); // kôd izostavljen clientOut.close (); serverOut.close (); System.out.println ("Veze zatvorene."); }}
Korak 19. Zatvorite poslužitelj
Veze su prekinute, ali poslužitelj i dalje radi. Kao
ServerSocket
nije povezan s bilo kojim streamom, potrebno ga je izričito zatvoriti pozivom
Zatvoriti()
metoda.
// kôd izostavljen import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); // kôd izostavljen System.out.println ("Komunikacija je spremna."); // kôd izostavljen clientOut.close (); serverOut.close (); System.out.println ("Veze zatvorene."); server.close (); }}
Korak 20. Zaustavljanje poslužitelja zapisnika
Za potrebe bilježenja, ispis na poslužitelju konzole je prekinut.
// kôd izostavljen import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; ServerSocket poslužitelj = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Poslužitelj pokrenut."); Socket client = nova utičnica (host, port); System.out.println ("Povezivanje sa poslužiteljem …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); // kôd izostavljen System.out.println ("Komunikacija je spremna."); // kôd izostavljen clientOut.close (); serverOut.close (); System.out.println ("Veze zatvorene."); server.close (); System.out.println ("Poslužitelj prekinut."); }}
Korak 21. Sastavite i pokrenite
Zapisivanje nam je omogućilo da znamo je li aplikacija uspješna ili ne. Očekivani učinak:
Poslužitelj je pokrenut. Povezivanje sa poslužiteljem … Veza je uspostavljena. Komunikacija je spremna. Poruka poslana poslužitelju: Hello World Poruka primljena od klijenta: Hello World Connections closed. Poslužitelj je prekinut.
U slučaju da vaš ispis nije poput gore navedenog, što se vjerojatno neće dogoditi, postoji nekoliko rješenja:
-
Ako izlaz stane na liniju
Veza uspostavljena.
i koriste se tokovi objekata, isperite svaki
ObjectOutputStream
- odmah nakon inicijalizacije jer zaglavlja iz nekog razloga nisu poslana.
-
Ako se ispisuje
java.net. BindException: Adresa koja se već koristi
- odaberite drugi broj porta jer se već koristi.
Savjeti
- Povezivanje s poslužiteljem na drugoj mreži vrši se povezivanjem na vanjsku IP adresu uređaja koji radi na poslužitelju koji ima proslijeđeni port.
- Povezivanje s poslužiteljem na istoj mreži vrši se ili povezivanjem na privatnu IP adresu uređaja koji radi na poslužitelju ili prosljeđivanjem porta i povezivanjem na vanjsku IP adresu uređaja.
- Postoje programi, poput Hamachija, koji omogućuju povezivanje s poslužiteljem na drugoj mreži bez prosljeđivanja porta, ali zahtijevaju instalaciju softvera na oba uređaja.
Primjeri
Mrežne aplikacije koje koriste blokiranje ulaza/izlaza moraju koristiti niti. Sljedeći primjeri prikazuju minimalističku implementaciju poslužitelja i klijenta s nitima. Mrežni kôd u biti je isti kao u članku, osim što su neki isječci sinkronizirani, premješteni u niti i obrađene iznimke.
Poslužitelj.java
import java.io. IOException; uvoz java.net. InetAddress; import java.net. ServerSocket; import java.net. SocketException; import java.net. UnknownHostException; import java.util. ArrayList; import java.util. Collections; uvoz java.util. List; /*** Klasa {@code Server} predstavlja krajnju točku poslužitelja u mreži. {@code Server} jednom vezan za određenu IP * adresu i port, uspostavlja veze s klijentima i može komunicirati s njima ili ih prekinuti. *
* Ova klasa nije sigurna. * * @version 1.0 * @see Client * @see Connection */ javna klasa Poslužitelj implementira Runnable {private ServerSocket server; privatni popis
veze; privatna nit niti; private final Object connectionsLock = novi Objekt (); /** * Konstruira {@code poslužitelj} koji stupa u interakciju s klijentima na navedenom imenu hosta i priključku s navedenim * traženim maksimalnim trajanjem u redu dolaznih klijenata. * * @param host Host Adresa za korištenje. * @param port Broj porta za korištenje. * @param backlog Tražena maksimalna duljina reda dolaznih klijenata. * @throws NetworkException Ako dođe do pogreške tijekom pokretanja poslužitelja. */ javni poslužitelj (Niz host, int port, int zaostatak) baca NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throw new NetworkException ("Naziv hosta nije moguće riješiti:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Broj porta mora biti između 0 i 65535 (uključujući))" + port); } catch (IOException e) {throw new NetworkException ("Poslužitelj se nije mogao pokrenuti.", e); } veze = Collections.synchronizedList (novi ArrayList ()); nit = nova nit (ovo); thread.start (); } /*** Konstruira {@code poslužitelj} koji komunicira s klijentima na navedenom imenu hosta i priključku. * * @param host Adresa hosta za vezanje. * @param port Broj porta za povezivanje. * @throw NetworkException Ako se tijekom pokretanja poslužitelja pojave pogreške. */ javni poslužitelj (String host, int port) baca NetworkException {this (host, port, 50); } /*** Sluša, prihvaća i registrira dolazne veze od klijenata. */ @Override public void run () {while (! Server.isClosed ()) {try {connections.add (nova veza (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Šalje podatke svim registriranim klijentima. * * @param podaci Podaci za slanje. * @throws IllegalStateException Ako se pokuša upisivanje podataka kada je poslužitelj izvan mreže. * @throws IllegalArgumentException Ako su podaci za slanje nuli. */ javno void emitiranje (Podaci objekta) {if (server.isClosed ()) {bacite novu IllegalStateException ("Podaci nisu poslani, poslužitelj je izvan mreže."); } if (data == null) {throw new IllegalArgumentException ("null data"); } sinkronizirano (connectionsLock) {za (Veza veze: veze) {pokušajte {connection.send (data); System.out.println ("Podaci uspješno poslani klijentu."); } catch (NetworkException e) {e.printStackTrace (); }}}} /*** Šalje poruku o prekidu veze i prekida vezu s navedenim klijentom. * * @param veza Klijent za prekid veze. * @throw NetworkException Ako dođe do pogreške tijekom prekida veze. */ public void disconnect (Connection connection) baca NetworkException {if (connections.remove (connection)) {connection.close (); }} /*** Šalje poruku o prekidu veze svim klijentima, prekida ih i prekida poslužitelj. */ public void close () baca NetworkException {synchronized (connectionsLock) {for (Connection connection: connections) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} veze.clear (); pokušajte {server.close (); } catch (IOException e) {throw new NetworkException ("Pogreška pri zatvaranju poslužitelja."); } konačno {thread.interrupt (); }} /*** Vraća je li poslužitelj online. * * @return Tačno ako je poslužitelj na mreži. U protivnom lažno. */ javni logički isOnline () {return! server.isClosed (); } /*** Vraća niz registriranih klijenata. */ public Connection getConnections () {synchronized (connectionsLock) {return connections.toArray (nova Connection [connections.size ()]); }}}
Klijent.java
import java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; /*** Klasa {@code Client} predstavlja krajnju točku klijenta u mreži. {@code Client}, jednom spojen na određeni * poslužitelj, zajamčeno će moći komunicirati samo s poslužiteljem. Hoće li drugi klijenti primiti podatke * ovisi o implementaciji poslužitelja. *
* Ova klasa nije sigurna. * * @verzija 1.0 * @vidi poslužitelj * @vidi vezu */ javna klasa Klijent {private Connection connection; /*** Konstruira {@code Client} povezan sa poslužiteljem na navedenom hostu i portu. * * @param host Adresa hosta za vezanje. * @param port Broj porta za povezivanje. * @throws NetworkException Ako dođe do pogreške tijekom pokretanja poslužitelja. */ javni klijent (Niz host, int port) baca NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Naziv hosta nije moguće riješiti:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Broj porta mora biti između 0 i 65535 (uključujući))" + port); } catch (IOException e) {throw new NetworkException ("Poslužitelj se nije mogao pokrenuti.", e); }} /*** Šalje podatke drugoj strani. * * @param podaci Podaci za slanje. * @throws NetworkException Ako pisanje u izlazni tok ne uspije. * @throws IllegalStateException Ako se pokuša upisati podatak kada je veza zatvorena. * @throws IllegalArgumentException Ako su podaci za slanje nuli. * @throws UnsupportedOperationException Ako se pokuša poslati nepodržana vrsta podataka. */ public void send (Podaci objekta) baca NetworkException {connection.send (data); } /*** Šalje poruku o prekidu veze s poslužiteljem i prekida vezu s njim. */ public void close () baca NetworkException {connection.close (); } /*** Vraća je li klijent spojen na poslužitelj. * * @return Istina ako je klijent spojen. U protivnom lažno. */ public boolean isOnline () {vrati vezu.isConnected (); } /*** Vraća instancu klijenta {@link Connection}. */ javna veza getConnection () {povratna veza; }}
Veza.java
import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; /** * Klasa {@code Connection} predstavlja vezu između poslužitelja i klijenta ili krajnju točku klijenta u mreži * {@code Connection}, nakon što se poveže, može razmjenjivati podatke s drugom stranom ili stranama, ovisno o tome na poslužitelju * implementacija. *
* Ova klasa nije sigurna. * * @version 1.0 * @see poslužitelj * @see klijent */ javna klasa Veza implementira Runnable {private Socket socket; privatni DataOutputStream out; privatni DataInputStream u; privatna nit niti; private final Object writeLock = novi Objekt (); privatni završni Objekt readLock = novi Objekt (); /*** Konstruira {@code Connection} pomoću tokova navedene {@link utičnice}. * * @param utičnica Utičnica za dohvaćanje tokova.*/ javna veza (utičnica utičnice) baca NetworkException {if (socket == null) {baca novu IllegalArgumentException ("null utičnica"); } this.socket = utičnica; isprobajte {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException ("Nije moguće pristupiti izlaznom toku.", e); } probati {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException ("Nije moguće pristupiti ulaznom toku.", e); } nit = nova nit (ovo); thread.start (); } /*** Čita poruke dok je veza s drugom stranom živa. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; byte bajtova; sinkronizirano (readLock) {identifikator = in.readInt (); int length = in.readInt (); if (duljina> 0) {bajti = novi bajt [duljina]; in.readFully (bajti, 0, bajti.dužina); } else {nastavi; }} prekidač (identifikator) {Identifikator slučaja. INTERNAL: Naredba niza = novi niz (bajtovi); if (command.equals ("prekini vezu")) {if (! socket.isClosed ()) {System.out.println ("Prekinut paket primljen."); probati {close (); } catch (NetworkException e) {return; } } } pauza; case Identifier. TEXT: System.out.println ("Poruka primljena:" + novi niz (bajtovi)); pauza; zadano: System.out.println ("Primljeni neprepoznati podaci."); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} /*** Šalje podatke drugoj strani. * * @param podaci Podaci za slanje. * @throws NetworkException Ako pisanje u izlazni tok ne uspije. * @throws IllegalStateException Ako se pokuša upisati podatak kada je veza zatvorena. * @throws IllegalArgumentException Ako su podaci za slanje nuli. * @throws UnsupportedOperationException Ako se pokuša poslati nepodržana vrsta podataka. */ public void send (Object data) baca NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Podaci nisu poslani, veza je zatvorena."); } if (data == null) {throw new IllegalArgumentException ("null data"); } int identifikator; byte bajtova; if (data instanceof String) {identifier = Identifier. TEXT; bytes = (((String) podaci).getBytes (); } else {throw new UnsupportedOperationException ("Nepodržana vrsta podataka:" + data.getClass ()); } probati {synchronized (writeLock) {out.writeInt (identifikator); out.writeInt (bytes.length); out.pisati (bajtova); out.flush (); }} catch (IOException e) {throw new NetworkException ("Podaci se ne mogu poslati.", e); }} /*** Šalje poruku o prekidu veze s drugom stranom i prekida vezu. */ public void close () baca NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Veza je već zatvorena."); } pokušajte {byte message = "prekinuti vezu".getBytes (); sinkronizirano (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.pisati (poruka); out.flush (); }} catch (IOException e) {System.out.println ("Poruka o prekidu veze nije mogla biti poslana."); } probati {synchronized (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Pogreška pri zatvaranju veze.", e); } konačno {thread.interrupt (); }} /*** Vraća je li veza s drugom stranom živa. * * @return Istina ako je veza živa. U protivnom lažno. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifikator.java
/** * Klasa {@code Identifier} sadrži konstante koje koristi {@link Connection} za serijalizaciju i deserijalizaciju podataka * poslanih preko mreže. * * @verzija 1.0 * @vidi vezu * / identifikator javne završne klase { / ** * Identifikator za interne poruke. */ javni statički završni int INTERNAL = 1; /*** Identifikator tekstualnih poruka. */ javni statički završni int TEXT = 2; }
NetworkException.java
/*** Klasa {@code NetworkException} označava pogrešku vezanu uz mrežu. * / javna klasa NetworkException proširuje Exception { / *** Konstruira {@code NetworkException} sa {@code null} kao porukom. * / public NetworkException () {} / *** Konstruira {@code NetworkException} s navedenom porukom. * * @param poruka Poruka za opis greške. */ public NetworkException (String poruka) {super (poruka); } /*** Konstruira {@code NetworkException} s navedenom porukom i uzrokom. * * @param poruka Poruka za opis greške. * @param uzrok Uzrok greške. */ public NetworkException (Niz poruka, Throwable uzrok) {super (poruka, uzrok); } /*** Konstruira {@code NetworkException} s navedenim uzrokom. * * @param uzrok Uzrok greške. */ public NetworkException (Throwable uzrok) {super (uzrok); }}
UsageExample.java
/*** Klasa {@code UsageExample} prikazuje upotrebu {@link Server} i {@link Client}. U ovim primjerima koristi se * {@link Thread#sleep (long)} kako bi se osiguralo izvršavanje svakog segmenta jer brzo pokretanje i zatvaranje dovodi do toga da se neki * segmenti ne izvršavaju. * * @verzija 1.0 * @see poslužitelj * @see klijent */ javna klasa UsageExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; Poslužitelj poslužitelja = novi poslužitelj (host, port); Klijent klijent = novi klijent (host, port); Navoj.spavanje (100L); client.send ("Zdravo."); server.broadcast ("Hej, druže!"); Navoj.spavanje (100L); server.disconnect (server.getConnections () [0]); // ili client.close () za prekid veze s poslužiteljem na strani klijenta.close (); }}