Pisanje koda koji se izvršava na određenom uređaju je vrlo zadovoljavajuće. 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 kontrolu prijenosa (TCP).
U ovom ćete članku postaviti aplikaciju koja će povezati vaše računalo sa samim sobom i, u biti, izluditi ga - razgovarati sa samim sobom. Naučit ćete i 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 dva toka koja se koriste u članku.
Prijenosi podataka
Tokovi podataka obrađuju primitivne tipove podataka i nizove. Podaci poslani putem tokova podataka moraju se 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 su slični tokovima podataka u tom aspektu, ali tokovi podataka osiguravaju da su podaci formatirani na način nezavisan od platforme, što je korisno jer će obje strane moći čitati poslane podatke.
Objekt Streams
Tokovi objekata obrađuju primitivne tipove podataka i objekte koje implementiraju
Serializable
interfejs. Podaci poslani preko tokova objekata automatski se serijaliziraju i deserijaliziraju što olakšava prijenos složenih podataka. No, objektni tokovi mogu komunicirati samo sa poslužiteljima i klijentima napisanim na Javi. Takođe,
ObjectOutputStream
nakon inicijalizacije, šalje zaglavlje u
InputStream
druge strane koja nakon inicijalizacije blokira izvršavanje dok se zaglavlje ne primi.
Koraci
Korak 1. Kreirajte klasu
Kreirajte klasu i dajte joj ime kako želite. U ovom članku će biti imenovan
NetworkAppExample
javna klasa NetworkAppExample {}
Korak 2. Kreirajte glavni metod
Kreirajte glavnu metodu i deklarirajte da bi mogla izazvati izuzetke
Izuzetak
tip i bilo koju njegovu podklasu - svi izuzeci. Ovo 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 servera
Ovaj primjer će koristiti lokalnu adresu hosta i proizvoljan broj porta. Broj porta 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 sistemski portovi.
javna klasa NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; }}
Korak 4. Kreirajte server
Poslužitelj je vezan za adresu i port i osluškuje dolazne veze. Na Javi,
ServerSocket
predstavlja krajnju točku na poslužitelju i njena funkcija je prihvaćanje novih veza.
ServerSocket
nema tokove za čitanje i slanje podataka jer ne predstavlja vezu između poslužitelja i klijenta.
import 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); }}
Korak 5. Početak poslužitelja dnevnika
Za potrebe evidentiranja, odštampajte na konzoli da je server pokrenut.
import 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); }}
Korak 6. Kreirajte klijenta
Klijent je vezan za adresu i port servera i sluša pakete (poruke) nakon uspostavljanja veze. Na Javi,
Socket
predstavlja ili krajnju točku na strani klijenta povezanu na poslužitelj ili vezu (sa poslužitelja) na klijenta i koristi se za komunikaciju sa stranom na drugom kraju.
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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); }}
Korak 7. Zabilježite pokušaj povezivanja
Za potrebe evidentiranja, ispišite na konzoli pokušaj povezivanja.
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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); }}
Korak 8. Uspostavite vezu
Klijenti se nikada neće povezati ako server ne posluša i ne prihvati, drugim riječima, uspostavi veze. U Javi se veze uspostavljaju pomoću
prihvatiti ()
metoda
ServerSocket
razred. Metoda će blokirati izvršavanje sve dok se klijent ne poveže.
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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); Socket connection = server.accept (); }}
Korak 9. Zabilježite uspostavljenu vezu
Za potrebe evidentiranja, ispišite na konzoli da je uspostavljena veza između poslužitelja i klijenta.
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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); Socket connection = server.accept (); System.out.println ("Veza uspostavljena."); }}
Korak 10. Pripremite komunikacijske tokove
Komunikacija se vrši putem tokova i, u ovoj aplikaciji, sirovi tokovi (povezivanje sa) servera (sa klijentom) i klijenta moraju biti povezani lancima na tokove podataka ili objekata. Upamtite, obje strane moraju koristiti istu vrstu prijenosa.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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
Kada se koristi više tokova objekata, ulazni tokovi moraju se inicijalizirati istim redoslijedom kao izlazni tokovi jer
ObjectOutputStream
šalje zaglavlje drugoj strani i
ObjectInputStream
blokira izvršavanje dok ne pročita zaglavlje.
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 evidentiranja, odštampajte na konzoli da je komunikacija spremna.
// kod 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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,
Zdravo svijete
tekst će biti poslan na server bilo kao
bajt
ili
String
. Deklarirajte varijablu tipa koja ovisi o korištenom toku. Upotreba
bajt
za tokove podataka i
String
za strujanje objekata.
-
Tokovi podataka
Koristeći tokove podataka, serijalizacija se vrši pretvaranjem objekata u primitivne tipove podataka ili
String
. U ovom slučaju,
String
pretvara se u
bajt
umesto pisanim korišćenjem
writeBytes ()
metoda koja pokazuje kako bi to bilo učinjeno s drugim objektima, poput slika ili drugih datoteka.
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 svete"; }}
Korak 13. Pošaljite poruku
Upišite podatke u izlazni tok i isperite tok kako biste bili sigurni da su podaci u potpunosti zapisani.
-
Tokovi podataka
Prvo je potrebno poslati dužinu poruke kako bi druga strana znala koliko bajtova treba pročitati. Nakon što se dužina pošalje kao primitivni cijeli broj, mogu se poslati bajtovi.
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Korak 14. Zabilježite poslanu poruku
Za potrebe evidentiranja, odštampajte na konzoli poruku koja je poslata.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 serveru:" + novi niz (messageOut)); }}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana serveru:" + messageOut); }}
Korak 15. Pročitajte poruku
Očitajte podatke iz ulaznog toka i pretvorite ih. Budući da znamo točno vrstu poslanih podataka, ili ćemo stvoriti
String
from
bajt
ili glumci
Object
to
String
bez provjere, ovisno o korištenom toku.
-
Tokovi podataka
Kako je prvo poslana dužina, a kasnije bajtovi, čitanje se mora obaviti istim redoslijedom. U slučaju da je dužina nula, nema se što čitati. Objekt se deserijalizira kada se bajtovi pretvore nazad u instancu, u ovom slučaju, datoteke
String
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 serveru:" + novi niz (messageOut)); int length = serverIn.readInt (); if (dužina> 0) {byte messageIn = novi bajt [dužina]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektni tokovi
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana serveru:" + messageOut); String messageIn = (String) serverIn.readObject (); }}
Korak 16. Zapišite pročitanu poruku
Za potrebe evidentiranja, odštampajte na konzoli primljenu poruku i odštampajte njen sadržaj.
-
Tokovi podataka
import java.io. DataInputStream; import java.io. DataOutputStream; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 serveru:" + novi niz (messageOut)); int length = serverIn.readInt (); if (dužina> 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; 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Poruka poslana serveru:" + messageOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Poruka primljena od klijenta:" + messageIn); }}
Korak 17. Prekinite veze
Veza se prekida kada jedna strana zatvori svoje tokove. U Javi, zatvaranjem izlaznog toka, zatvaraju se i povezani priključak i ulazni tok. Jednom kada strana na drugom kraju sazna da je veza prekinuta, mora zatvoriti i svoj izlazni tok kako bi spriječila curenje memorije.
// kod 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 evidentiranja, veze za ispis na konzolu su prekinute.
// kod 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 server je i dalje pokrenut. As
ServerSocket
nije povezan s bilo kojim tokom, potrebno ga je izričito zatvoriti pozivom
zatvori ()
metoda.
// kod 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 dnevnika
Za potrebe evidentiranja, štampanje na poslužitelju konzole je prekinuto.
// kod 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 server = novi ServerSocket (port, 50, InetAddress.getByName (host)); System.out.println ("Server pokrenut."); Socket client = novi Socket (host, port); System.out.println ("Povezivanje sa serverom …"); 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 ("Server je zatvoren."); }}
Korak 21. Prevedite i pokrenite
Evidentiranje nam je omogućilo da znamo je li aplikacija uspješna ili ne. Očekivani učinak:
Server pokrenut. Povezivanje sa serverom … Veza uspostavljena. Komunikacija je spremna. Poruka poslana na server: Hello World Poruka primljena od klijenta: Hello World Connections closed. Server je ukinut.
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 sa serverom na drugoj mreži vrši se povezivanjem na spoljnu IP adresu uređaja koji radi na serveru koji ima prosleđeni port.
- Povezivanje sa serverom na istoj mreži vrši se ili povezivanjem na privatnu IP adresu uređaja koji radi na serveru ili prosljeđivanjem porta i povezivanjem na vanjsku IP adresu uređaja.
- Postoje programi, poput Hamachija, koji omogućuju povezivanje sa serverom 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. Kôd za umrežavanje u osnovi je isti kao u članku, osim što su neki isječci sinhronizirani, premješteni u niti i obrađeni izuzeci.
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; /*** Klasa {@code Server} predstavlja krajnju tačku servera 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 Server implementira Runnable {private ServerSocket server; privatna lista
veze; privatna nit; private final Object connectionsLock = new Object (); /** * Konstruiše {@code Server} koji komunicira sa klijentima na navedenom imenu hosta i portu sa navedenom * traženom maksimalnom dužinom reda dolaznih klijenata. * * @param host Adresa hosta za upotrebu. * @param port Broj porta za upotrebu. * @param backlog Tražena maksimalna dužina reda dolaznih klijenata. * @throws NetworkException Ako dođe do greške pri pokretanju servera. */ 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 ("Ime hosta nije moguće reš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 ("Server nije moguće pokrenuti.", e); } veze = Collections.synchronizedList (novi ArrayList ()); nit = nova nit (ovo); thread.start (); } /*** Konstruira {@code Server} koji komunicira s klijentima na navedenom imenu hosta i portu. * * @param host Adresa hosta za vezivanje. * @param port Broj porta za vezivanje. * @throws NetworkException Ako dođe do grešaka prilikom pokretanja poslužitelja. */ javni server (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 server van mreže. * @throws IllegalArgumentException Ako su podaci za slanje nuli. */ javno void emitovanje (Podaci objekta) {if (server.isClosed ()) {baci novu IllegalStateException ("Podaci nisu poslati, server je van mreže."); } if (data == null) {throw new IllegalArgumentException ("null data"); } sinhronizovano (connectionsLock) {za (Veza veze: veze) {probajte {connection.send (data); System.out.println ("Podaci su 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 greške pri prekidu 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 server. */ public void close () baca NetworkException {synchronized (connectionsLock) {for (Connection connection: connections) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} links.clear (); probajte {server.close (); } catch (IOException e) {throw new NetworkException ("Greška pri zatvaranju servera."); } konačno {thread.interrupt (); }} /*** Vraća da li je server na mreži. * * @return Tačno ako je server na mreži. Netačno, inače. */ public boolean isOnline () {return! server.isClosed (); } /*** Vraća niz registriranih klijenata. */ 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; /*** Klasa {@code Client} predstavlja krajnju tačku klijenta u mreži. {@code Client}, kada se jednom poveže na određeni * server, garantuje se da će moći komunicirati samo sa serverom. Hoće li drugi klijenti primiti podatke * ovisi o implementaciji poslužitelja. *
* Ova klasa nije sigurna. * * @verzija 1.0 * @see Server * @see Connection */ javna klasa Client {private Connection connection; /*** Konstruira {@code Client} povezan sa serverom na navedenom hostu i portu. * * @param host Adresa hosta za vezivanje. * @param port Broj porta za vezivanje. * @throws NetworkException Ako dođe do greške pri pokretanju servera. */ javni klijent (string niz, int port) baca NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Ime hosta nije moguće reš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 ("Server nije moguće pokrenuti.", e); }} /*** Šalje podatke drugoj strani. * * @param podaci Podaci za slanje. * @throws NetworkException Ako pisanje na 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žani tip podataka. */ public void send (Podaci objekta) baca NetworkException {connection.send (data); } /*** Šalje poruku o prekidu veze s serverom i prekida vezu s njim. */ public void close () baca NetworkException {connection.close (); } /*** Vraća da li je klijent povezan sa serverom. * * @return Tačno ako je klijent povezan. Netačno, inače. */ public boolean isOnline () {return connection.isConnected (); } /*** Vraća {@link Connection} instancu klijenta. */ javna veza getConnection () {povratna veza; }}
Connection.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 ili vezu između servera i klijenta ili krajnju tač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 implementaciji servera *. *
* Ova klasa nije sigurna. * * @version 1.0 * @see Server * @see Client */ javna klasa Veza implementira Runnable {private Socket socket; privatni DataOutputStream out; privatni DataInputStream u; privatna nit; private final Object writeLock = new Object (); private final Object readLock = new Object (); /*** Konstruira {@code Connection} koristeći tokove 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 void run () {while (! Socket.isClosed ()) {try {int identifier; byte bajtova; sinhronizovano (readLock) {identifikator = in.readInt (); int length = in.readInt (); if (dužina> 0) {bajtova = novi bajt [dužina]; in.readFully (bajti, 0, bajtovi.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."); probajte {close (); } catch (NetworkException e) {return; }}} break; case Identifier. TEXT: System.out.println ("Poruka primljena:" + novi niz (bajtovi)); break; default: System.out.println ("Neprepoznati podaci primljeni."); }} 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 na 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žani tip podataka. */ public void send (Object data) baca NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Podaci nisu poslati, veza je zatvorena."); } if (data == null) {throw new IllegalArgumentException ("null data"); } int identifikator; byte bajtova; if (data instanceof String) {identifier = Identifier. TEXT; bajtovi = ((String) podaci).getBytes (); } else {throw new UnsupportedOperationException ("Nepodržani tip podataka:" + data.getClass ()); } probajte {synchronized (writeLock) {out.writeInt (identifikator); out.writeInt (bytes.length); out.write (bajtovi); out.flush (); }} catch (IOException e) {throw new NetworkException ("Podaci se ne mogu poslati.", e); }} /*** Šalje poruku o prekidu veze sa drugom stranom i prekida vezu. */ public void close () baca NetworkException {if (socket.isClosed ()) {baca novu IllegalStateException ("Veza je već zatvorena."); } probati {byte message = "prekinuti vezu".getBytes (); sinhronizovano (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.write (poruka); out.flush (); }} catch (IOException e) {System.out.println ("Poruka o prekidu veze nije mogla biti poslana."); } probajte {synchronized (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Greška pri zatvaranju veze.", e); } konačno {thread.interrupt (); }} /*** Vraća da li je veza sa drugom stranom živa ili ne. * * @return Tačno ako je veza živa. Netačno, inače. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifier.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 * / javni završni identifikator 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 grešku vezanu za mrežu. * / javna klasa NetworkException proširuje Exception { / *** Konstruira {@code NetworkException} sa {@code null} kao porukom. * / public NetworkException () {} / *** Konstruira {@code NetworkException} sa navedenom porukom. * * @param poruka Poruka za opis greške. */ public NetworkException (String poruka) {super (poruka); } /*** Konstruira {@code NetworkException} sa navedenom porukom i uzrokom. * * @param poruka Poruka za opis greške. * @param uzrok Uzrok greške. */ public NetworkException (string poruka, Throwable uzrok) {super (poruka, uzrok); } /*** Konstruira {@code NetworkException} s navedenim uzrokom. * * @param uzrok Uzrok greške. */ public NetworkException (Bacivi uzrok) {super (uzrok); }}
UsageExample.java
/*** Klasa {@code UsageExample} prikazuje upotrebu {@link Server} i {@link Client}. U ovim primjerima se koristi * {@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. * * @version 1.0 * @see Server * @see Client */ javna klasa UsageExample {public static void main (String args) throws Exception {String host = "localhost"; int port = 10430; Server server = novi server (host, port); Klijent klijent = novi klijent (host, port); Thread.sleep (100L); client.send ("Zdravo."); server.broadcast ("Hej, momče!"); Thread.sleep (100L); server.disconnect (server.getConnections () [0]); // ili client.close () za prekid veze sa serverom na strani klijenta.close (); }}