Scrierea codului care se execută pe un anumit dispozitiv este foarte satisfăcătoare. Dar, scrierea unui cod care se execută pe mai multe dispozitive care comunică între ele este pur și simplu afirmatoare de viață. Acest articol vă va învăța cum să vă conectați și să schimbați mesaje prin rețea utilizând protocolul de control al transmisiei (TCP).
În acest articol, veți configura o aplicație care vă va conecta computerul la el însuși și, în esență, îl va face nebun - vorbiți cu el însuși. De asemenea, veți afla diferența dintre cele două fluxuri cele mai utilizate pentru rețea în Java și modul în care acestea funcționează.
Fluxuri de date și obiecte
Înainte de a vă scufunda în cod, diferența dintre cele două fluxuri utilizate în articol trebuie să fie distinsă.
Fluxuri de date
Fluxurile de date procesează tipuri și șiruri de date primitive. Datele trimise prin fluxuri de date trebuie să fie serializate manual și deserializate, ceea ce face mai dificilă transferul de date complexe. Dar fluxurile de date pot comunica cu servere și clienți scrise în alte limbi decât Java. Fluxurile brute sunt similare fluxurilor de date în acest aspect, dar fluxurile de date asigură faptul că datele sunt formatate într-un mod independent de platformă, ceea ce este benefic, deoarece ambele părți vor putea citi datele trimise.
Fluxuri de obiecte
Fluxurile de obiecte procesează tipuri de date primitive și obiecte care implementează
Serializabil
interfață. Datele trimise prin fluxuri de obiecte sunt serializate și deserializate automat, ceea ce face mai ușor transferul de date complexe. Dar fluxurile de obiecte pot comunica numai cu servere și clienți scrise în Java. De asemenea,
ObjectOutputStream
la inițializare, trimite un antet la
InputStream
a celeilalte părți care, la inițializare, blochează execuția până la primirea antetului.
Pași
Pasul 1. Creați o clasă
Creați o clasă și denumiți-o după cum doriți. În acest articol, va fi numit
NetworkAppExample
clasă publică NetworkAppExample {}
Pasul 2. Creați o metodă principală
Creați o metodă principală și declarați că ar putea genera excepții de la
Excepție
tipul și orice subclasă a acestuia - toate excepțiile. Aceasta este considerată o practică proastă, dar este acceptabilă pentru exemplele barebone.
public class NetworkAppExample {public static void main (String args) throws Exception {}}
Pasul 3. Declarați adresa serverului
Acest exemplu va folosi adresa gazdă locală și un număr de port arbitrar. Numărul portului trebuie să fie cuprins între 0 și 65535 (inclusiv). Cu toate acestea, numerele de porturi care trebuie evitate variază de la 0 la 1023 (inclusiv) deoarece sunt porturi de sistem rezervate.
public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; }}
Pasul 4. Creați un server
Serverul este legat de adresă și port și ascultă conexiunile primite. În Java,
ServerSocket
reprezintă punctul final al serverului și funcția sa este acceptarea de noi conexiuni.
ServerSocket
nu are fluxuri pentru citirea și trimiterea datelor, deoarece nu reprezintă conexiunea dintre un server și un client.
import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); }}
Pasul 5. Începutul serverului de jurnal
În scopuri de înregistrare, imprimați pe consolă că serverul a fost pornit.
import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); }}
Pasul 6. Creați un client
Clientul este legat de adresa și portul unui server și ascultă pachetele (mesajele) după stabilirea conexiunii. În Java,
Priză
reprezintă fie un punct final al clientului conectat la server, fie o conexiune (de la server) la client și este utilizat pentru a comunica cu partea de la celălalt capăt.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); }}
Pasul 7. Încercați conectarea jurnalului
În scopuri de înregistrare, tipăriți pe consolă că s-a încercat conectarea.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); }}
Pasul 8. Stabiliți conexiunea
Clienții nu se vor conecta niciodată, cu excepția cazului în care serverul ascultă și acceptă, altfel spus, stabilește conexiuni. În Java, conexiunile sunt stabilite folosind
Accept()
Metodă de
ServerSocket
clasă. Metoda va bloca execuția până când un client se conectează.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); }}
Pasul 9. Înregistrați conexiunea stabilită
În scopuri de înregistrare, tipăriți pe consolă că conexiunea dintre server și client a fost stabilită.
import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); }}
Pasul 10. Pregătiți fluxuri de comunicare
Comunicarea se face prin fluxuri și, în această aplicație, fluxurile brute de (conexiune de la) server (la client) și client trebuie să fie înlănțuite fie cu fluxuri de date, fie cu obiecte. Amintiți-vă, ambele părți trebuie să utilizeze același tip de flux.
-
Fluxuri de date
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); }}
-
Fluxuri de obiecte
Când sunt utilizate mai multe fluxuri de obiecte, fluxurile de intrare trebuie inițializate în aceeași ordine ca fluxurile de ieșire, deoarece
ObjectOutputStream
trimite un antet către cealaltă parte și
ObjectInputStream
blochează execuția până când citește antetul.
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); }}
Ordinea specificată în codul de mai sus ar putea fi mai ușor de reținut - inițializați mai întâi fluxurile de ieșire, apoi introduceți fluxurile în aceeași ordine. Cu toate acestea, o altă ordine pentru inițializarea fluxurilor de obiecte este următoarea:
ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ());
Pasul 11. Înregistrați-vă că comunicarea este gata
În scopuri de înregistrare, tipăriți pe consolă că comunicarea este gata.
// cod omis import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); // cod omis System.out.println ("Comunicarea este gata."); }}
Pasul 12. Creați un mesaj
În această aplicație,
Salut Lume
textul va fi trimis la server fie ca
octet
sau
Şir
. Declarați o variabilă de tipul care depinde de fluxul utilizat. Utilizare
octet
pentru fluxurile de date și
Şir
pentru fluxurile de obiecte.
-
Fluxuri de date
Folosind fluxuri de date, serializarea se face prin conversia obiectelor în tipuri de date primitive sau a
Şir
. În acest caz,
Şir
este convertit în
octet
în loc de scris folosind
writeBytes ()
metodă pentru a arăta cum s-ar face cu alte obiecte, cum ar fi imagini sau alte fișiere.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); octet messageOut = "Hello World".getBytes (); }}
-
Fluxuri de obiecte
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); String messageOut = "Hello World"; }}
Pasul 13. Trimiteți mesajul
Scrieți datele în fluxul de ieșire și spălați fluxul pentru a vă asigura că datele au fost scrise în întregime.
-
Fluxuri de date
Lungimea unui mesaj trebuie trimisă mai întâi, astfel încât cealaltă parte să știe câte octeți trebuie să citească. După ce lungimea este trimisă ca tip întreg primitiv, pot fi trimiși octeți.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); octet messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (mesajOut); clientOut.flush (); }}
-
Fluxuri de obiecte
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); String messageOut = "Hello World"; clientOut.writeObject (mesajOut); clientOut.flush (); }}
Pasul 14. Înregistrați mesajul trimis
În scopuri de înregistrare, imprimați pe consolă că mesajul a fost trimis.
-
Fluxuri de date
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); octet messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + șir nou (mesajOut)); }}
-
Fluxuri de obiecte
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); String messageOut = "Hello World"; clientOut.writeObject (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + mesajOut); }}
Pasul 15. Citiți mesajul
Citiți datele din fluxul de intrare și convertiți-le. Deoarece știm exact tipul de date trimise, fie vom crea un
Şir
din
octet
sau turnat
Obiect
la
Şir
fără verificare, în funcție de fluxul utilizat.
-
Fluxuri de date
Deoarece lungimea a fost trimisă mai întâi și octeții după aceea, citirea trebuie făcută în aceeași ordine. În cazul în care lungimea este zero, nu este nimic de citit. Obiectul este deserializat atunci când octeții sunt convertiți înapoi într-o instanță, în acest caz, a
Şir
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); octet messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + șir nou (mesajOut)); lungime int = serverIn.readInt (); if (lungime> 0) {octet messageIn = octet nou [lungime]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Fluxuri de obiecte
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); String messageOut = "Hello World"; clientOut.writeObject (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + mesajOut); String messageIn = (String) serverIn.readObject (); }}
Pasul 16. Jurnal mesaj citit
În scopuri de înregistrare, tipăriți pe consolă mesajul care a fost primit și imprimați conținutul acestuia.
-
Fluxuri de date
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); DataOutputStream clientOut = new DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = nou DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); octet messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + șir nou (mesajOut)); lungime int = serverIn.readInt (); if (lungime> 0) {octet messageIn = octet nou [lungime]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Mesaj primit de la client:" + șir nou (messageIn)); }}}
-
Fluxuri de obiecte
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); ObjectOutputStream clientOut = new ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nou ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nou ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nou ObjectInputStream (connection.getInputStream ()); System.out.println ("Comunicarea este gata."); String messageOut = "Hello World"; clientOut.writeObject (mesajOut); clientOut.flush (); System.out.println ("Mesaj trimis la server:" + mesajOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Mesaj primit de la client:" + messageIn); }}
Pasul 17. Deconectați conexiunile
Conexiunea este deconectată atunci când o parte își închide fluxurile. În Java, prin închiderea fluxului de ieșire, socketul și fluxul de intrare sunt închise, de asemenea. Odată ce o parte din celălalt capăt află că conexiunea este moartă, trebuie să-și închidă fluxul de ieșire, de asemenea, pentru a preveni scurgerile de memorie.
// cod omis import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); // cod omis System.out.println ("Comunicarea este gata."); // cod omis clientOut.close (); serverOut.close (); }}
Pasul 18. Deconectarea jurnalului
În scopuri de înregistrare, tipărirea la conexiunea consolă a fost deconectată.
// cod omis import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); // cod omis System.out.println ("Comunicarea este gata."); // cod omis clientOut.close (); serverOut.close (); System.out.println ("Conexiuni închise."); }}
Pasul 19. Terminați serverul
Conexiunile sunt deconectate, dar serverul este în continuare funcțional. La fel de
ServerSocket
nu este asociat cu niciun flux, trebuie închis în mod explicit prin apelare
închide()
metodă.
// cod omis import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); // cod omis System.out.println ("Comunicarea este gata."); // cod omis clientOut.close (); serverOut.close (); System.out.println ("Conexiuni închise."); server.close (); }}
Pasul 20. Terminare server server
În scopuri de înregistrare, imprimarea pe serverul consolă a fost terminată.
// cod omis import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; ServerSocket server = serverSocket nou (port, 50, InetAddress.getByName (gazdă)); System.out.println ("Serverul a pornit."); Socket client = Socket nou (gazdă, port); System.out.println ("Conectarea la server …"); Conexiune socket = server.accept (); System.out.println ("Conexiune stabilită."); // cod omis System.out.println ("Comunicarea este gata."); // cod omis clientOut.close (); serverOut.close (); System.out.println ("Conexiuni închise."); server.close (); System.out.println ("Server terminat."); }}
Pasul 21. Compilați și rulați
Logarea ne-a permis să știm dacă aplicația a avut succes sau nu. Ieșire preconizată:
Serverul a început. Conectarea la server … Conexiunea stabilită. Comunicarea este gata. Mesaj trimis la server: Hello World Mesaj primit de la client: Hello World Conexiuni închise. Server terminat.
În cazul în care rezultatul dvs. nu este ca cel de mai sus, ceea ce este puțin probabil să se întâmple, există câteva soluții:
-
Dacă ieșirea se oprește la linie
Conexiune stabilita.
și fluxurile de obiecte sunt utilizate, spălați fiecare
ObjectOutputStream
- imediat după inițializare deoarece anteturile, dintr-un anumit motiv, nu au fost trimise.
-
Dacă ieșirea se imprimă
java.net. BindException: Adresa deja utilizată
- alegeți un număr de port diferit, deoarece cel specificat este deja utilizat.
sfaturi
- Conectarea la un server dintr-o altă rețea se face prin conectarea la adresa IP externă a unui dispozitiv care rulează serverul care are un port redirecționat.
- Conectarea la un server din aceeași rețea se face fie prin conectarea la adresa IP privată a unui dispozitiv care rulează serverul, fie prin redirecționarea unui port și conectarea la adresa IP externă a dispozitivului.
- Există programe software, cum ar fi Hamachi, care permit conectarea la server pe o altă rețea fără redirecționarea unui port, dar necesită instalarea software-ului pe ambele dispozitive.
Exemple
Aplicațiile de rețea care utilizează blocarea de intrare / ieșire trebuie să utilizeze fire. Următoarele exemple arată o implementare minimalistă de server și client cu fire. Codul de rețea este în esență același cu cel din articol, cu excepția faptului că unele fragmente au fost sincronizate, mutate în fire și excepțiile sunt tratate.
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; / ** * Clasa {@code Server} reprezintă un punct final al serverului într-o rețea. {@code Server} odată legat de o anumită adresă IP * și port, stabilește conexiuni cu clienții și este capabil să comunice cu aceștia sau să le deconecteze. *
* Această clasă este threadsafe. * * @version 1.0 * @see Client * @see Connection * / public class Server implements Runnable {private ServerSocket server; Listă privată
conexiuni; fir Thread privat; private final Object connectionsLock = new Object (); / ** * Construiește un {@code Server} care interacționează cu clienții pe numele de gazdă și portul specificat cu lungimea maximă solicitată * specificată pentru o coadă de clienți primiți. * * @param Adresa gazdei de utilizat. * @param port Număr de port de utilizat. * @param backlog A solicitat lungimea maximă a cozii clienților de intrare. * @throws NetworkException Dacă apare o eroare la pornirea unui server. * / Server public (String host, int port, int backlog) aruncă NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throw new NetworkException ("Numele gazdei nu a putut fi rezolvat:" + gazda, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Numărul portului trebuie să fie între 0 și 65535 (inclusiv):" + port); } catch (IOException e) {throw new NetworkException ("Serverul nu a putut fi pornit.", e); } conexiuni = Collections.synchronizedList (new ArrayList ()); fir = fir nou (acesta); thread.start (); } / ** * Construiește un {@code Server} care interacționează cu clienții pe numele gazdă și portul specificat. * * @param Adresa gazdei de legat. * @param port Număr de port de legat. * @throws NetworkException Dacă apar erori la pornirea unui server. * / Server public (String host, int port) aruncă NetworkException {aceasta (gazdă, port, 50); } / ** * Ascultă, acceptă și înregistrează conexiunile primite de la clienți. * / @Override public void run () {while (! Server.isClosed ()) {try {connections.add (new Connection (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). egal cu ("Socket închis")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} / ** * Trimite date tuturor clienților înregistrați. * * @param date Date de trimis. * @throws IllegalStateException Dacă se încearcă scrierea datelor când serverul este offline. * @throws IllegalArgumentException Dacă datele de trimis sunt nule. * / difuzare publică nulă (date obiect) {if (server.isClosed ()) {aruncă o nouă IllegalStateException („Datele nu au fost trimise, serverul este offline.”); } if (data == null) {aruncă o nouă excepție IllegalArgumentException („date nule”); } sincronizat (conexiuniLock) {pentru (Conexiune conexiune: conexiuni) {încercați {connection.send (date); System.out.println ("Datele trimise clientului cu succes."); } catch (NetworkException e) {e.printStackTrace (); }}}} / ** * Trimite un mesaj de deconectare și deconectează clientul specificat. * * @param connection Client de deconectat. * @throws NetworkException Dacă apare o eroare la închiderea conexiunii. * / public void disconnect (conexiune conexiune) lansează NetworkException {if (connections.remove (connection)) {connection.close (); }} / ** * Trimite un mesaj de deconectare tuturor clienților, îi deconectează și termină serverul. * / public void close () aruncă NetworkException {synchronized (connectionsLock) {for (Conexiune conexiune: conexiuni) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} connections.clear (); încercați {server.close (); } catch (IOException e) {throw new NetworkException ("Eroare la închiderea serverului."); } în cele din urmă {thread.interrupt (); }} / ** * Returnează dacă serverul este sau nu online. * * @return True dacă serverul este online. Fals, altfel. * / public boolean isOnline () {return! server.isClosed (); } / ** * Returnează o serie de clienți înregistrați. * / 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; / ** * Clasa {@code Client} reprezintă un punct final al clientului într-o rețea. {@code Client}, odată conectat la un anumit server *, este garantat că va putea comunica numai cu serverul. Dacă alți clienți primesc sau nu datele * depinde de implementarea serverului. *
* Această clasă este threadsafe. * * @version 1.0 * @see Server * @see Connection * / public class Client {private Connection connection; / ** * Construiește un {@code Client} conectat la server pe gazda și portul specificat. * * @param Adresa gazdei de legat. * @param port Număr de port de legat. * @throws NetworkException Dacă apare o eroare la pornirea unui server. * / public Client (String host, int port) aruncă NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Numele gazdei nu a putut fi rezolvat:" + gazda, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Numărul portului trebuie să fie între 0 și 65535 (inclusiv):" + port); } catch (IOException e) {throw new NetworkException ("Serverul nu a putut fi pornit.", e); }} / ** * Trimite date celeilalte părți. * * @param date Date de trimis. * @throws NetworkException Dacă scrierea în fluxul de ieșire eșuează. * @throws IllegalStateException Dacă se încearcă scrierea datelor când conexiunea este închisă. * @throws IllegalArgumentException Dacă datele de trimis sunt nule. * @throws UnsupportedOperationException Dacă se încearcă trimiterea unui tip de date neacceptat. * / public nul de trimitere (date obiect) aruncă NetworkException {connection.send (date); } / ** * Trimite un mesaj de deconectare la server și închide conexiunea cu acesta. * / public void close () aruncă NetworkException {connection.close (); } / ** * Returnează dacă clientul este sau nu conectat la server. * * @return True dacă clientul este conectat. Fals, altfel. * / public boolean isOnline () {return connection.isConnected (); } / ** * Returnează instanța {@link Connection} a clientului. * / public Connection getConnection () {returnare conexiune; }}
Conexiune.java
import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; / ** * Clasa {@code Connection} reprezintă fie o conexiune de la server la client, fie un punct final al clientului într-o rețea * {@code Connection}, odată conectat, poate schimba date cu alte părți sau părți, în funcție de pe un server * implementare. *
* Această clasă este threadsafe. * * @version 1.0 * @see Server * @see Client * / public class Connection implements Runnable {private Socket socket; private DataOutputStream out; private DataInputStream în; fir Thread privat; private final Object writeLock = new Object (); private final Object readLock = new Object (); / ** * Construiește {@code Connection} folosind fluxurile unui {@link Socket} specificat. * * @param socket Socket pentru a prelua fluxurile.* / Conexiune publică (socket socket) aruncă NetworkException {if (socket == null) {aruncă o nouă IllegalArgumentException ("socket null"); } this.socket = socket; încercați {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException („Nu s-a putut accesa fluxul de ieșire.”, e); } încercați {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException („Nu s-a putut accesa fluxul de intrare.”, e); } fir = fir nou (acesta); thread.start (); } / ** * Citește mesajele în timp ce conexiunea cu cealaltă parte este activă. * / @Override public void run () {while (! Socket.isClosed ()) {try {int identificator; byte bytes; sincronizat (readLock) {identificator = in.readInt (); lungime int = in.readInt (); if (lungime> 0) {octeți = octet nou [lungime]; in.readFully (octeți, 0, octeți lungime); } else {continue; }} switch (identificator) {case Identifier. INTERNAL: String command = new String (bytes); if (command.equals ("deconectați")) {if (! socket.isClosed ()) {System.out.println ("Pachetul de deconectare primit."); încercați {close (); } catch (NetworkException e) {return; } } } pauză; identificator de caz. TEXT: System.out.println ("Mesaj primit:" + șir nou (octeți)); pauză; implicit: System.out.println ("Date nerecunoscute primite."); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket închis")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} / ** * Trimite date către cealaltă parte. * * @param date Date de trimis. * @throws NetworkException Dacă scrierea în fluxul de ieșire eșuează. * @throws IllegalStateException Dacă se încearcă scrierea datelor când conexiunea este închisă. * @throws IllegalArgumentException Dacă datele de trimis sunt nule. * @throws UnsupportedOperationException Dacă se încearcă trimiterea unui tip de date neacceptat. * / public void send (Object data) lansează NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Datele nu au fost trimise, conexiunea este închisă."); } if (data == null) {aruncă o nouă excepție IllegalArgumentException („date nule”); } identificator int; byte bytes; if (instance instanceof String) {identificator = Identificator. TEXT; octeți = ((Șir) date).getBytes (); } else {throw new UnsupportedOperationException ("Tip de date neacceptat:" + data.getClass ()); } încercați {synchronized (writeLock) {out.writeInt (identificator); out.writeInt (bytes.length); out.write (octeți); out.flush (); }} catch (IOException e) {throw new NetworkException ("Datele nu au putut fi trimise.", e); }} / ** * Trimite un mesaj de deconectare către și oprește conexiunea cu cealaltă parte. * / public void close () aruncă NetworkException {if (socket.isClosed ()) {aruncă o nouă IllegalStateException ("Conexiunea este deja închisă."); } try {byte message = "disconnect".getBytes (); sincronizat (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.write (mesaj); out.flush (); }} catch (IOException e) {System.out.println ("Mesajul de deconectare nu a putut fi trimis."); } încercați {synchronized (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Eroare la închiderea conexiunii.", e); } în cele din urmă {thread.interrupt (); }} / ** * Returnează dacă conexiunea cu cealaltă parte este sau nu activă. * * @return Adevărat dacă conexiunea este vie. Fals, altfel. * / public boolean isConnected () {return! socket.isClosed (); }}
Identificator.java
/ ** * Clasa {@code Identifier} conține constante utilizate de {@link Connection} pentru serializarea și deserializarea datelor * trimise prin rețea. * * @version 1.0 * @vege Connection * / public final class Identifier {/ ** * Identifier pentru mesaje interne. * / public static final int INTERN = 1; / ** * Identificator pentru mesaje text. * / public static final int TEXT = 2; }
NetworkException.java
/ ** * Clasa {@code NetworkException} indică o eroare legată de rețea. * / public class NetworkException extends Exception {/ ** * Construiește un {@code NetworkException} cu {@code null} ca mesaj. * / public NetworkException () {} / ** * Construiește un {@code NetworkException} cu mesajul specificat. * * @param message Un mesaj pentru a descrie eroarea. * / public NetworkException (String message) {super (mesaj); } / ** * Construiește o {@code NetworkException} cu mesajul și cauza specificate. * * @param message Un mesaj pentru a descrie eroarea. * @param cauza O cauză de eroare. * / public NetworkException (String message, Throwable cause) {super (mesaj, cauză); } / ** * Construiește o {@code NetworkException} cu cauza specificată. * * @param cauza O cauză de eroare. * / public NetworkException (cauza aruncabilă) {super (cauza); }}
UsageExample.java
/ ** * Clasa {@code UsageExample} arată utilizarea {@link Server} și {@link Client}. Acest exemplu folosește * {@link Thread # sleep (long)} pentru a vă asigura că fiecare segment este executat, deoarece pornirea și închiderea rapidă fac ca unele * segmente să nu se execute. * * @version 1.0 * @see Server * @see Client * / public class UsageExample {public static void main (String args) throws Exception {String host = "localhost"; port int = 10430; Server server = server nou (gazdă, port); Client client = client nou (gazdă, port); Thread.sleep (100L); client.send ("Bună ziua"); server.broadcast ("Hei, fella!"); Thread.sleep (100L); server.disconnect (server.getConnections () [0]); // sau client.close () pentru a vă deconecta de la server.close () partea clientului; }}