Koda rakstīšana, kas tiek izpildīta noteiktā ierīcē, ir ļoti apmierinoša. Bet koda rakstīšana, kas tiek izpildīta vairākās ierīcēs, kas savstarpēji sazinās, ir vienkārši dzīvību apliecinoša. Šis raksts iemācīs jums izveidot savienojumu un apmainīties ar ziņojumiem tīklā, izmantojot pārraides vadības protokolu (TCP).
Šajā rakstā jūs iestatīsit lietojumprogrammu, kas savienos jūsu datoru ar sevi un būtībā padarīs to traku - runājiet ar sevi. Jūs uzzināsit arī atšķirību starp divām Java tīklā visplašāk izmantotajām straumēm un to darbību.
Datu un objektu straumes
Pirms ienirt kodā, ir jānošķir atšķirība starp abām rakstā izmantotajām plūsmām.
Datu straumes
Datu plūsmas apstrādā primitīvus datu tipus un virknes. Dati, kas nosūtīti, izmantojot datu plūsmas, ir manuāli jāserializē un jāatserializē, kas apgrūtina sarežģītu datu pārsūtīšanu. Tomēr datu plūsmas var sazināties ar serveriem un klientiem, kas rakstīti citās valodās, nevis Java. Neapstrādātas plūsmas šajā ziņā ir līdzīgas datu plūsmām, taču datu plūsmas nodrošina, ka dati tiek formatēti no platformas neatkarīgā veidā, kas ir izdevīgi, jo abas puses varēs nolasīt nosūtītos datus.
Objektu straumes
Objektu straumes apstrādā primitīvus datu tipus un objektus, kurus īsteno
Serializējams
interfeisu. Dati, kas tiek nosūtīti pa objektu plūsmām, tiek automātiski sērijveidoti un deserializēti, kas atvieglo sarežģītu datu pārsūtīšanu. Bet objektu straumes var sazināties tikai ar serveriem un klientiem, kas rakstīti Java valodā. Arī
ObjectOutputStream
pēc inicializācijas nosūta galveni uz
InputStream
no otras puses, kas pēc inicializācijas bloķē izpildi, līdz tiek saņemta galvene.
Soļi
1. solis. Izveidojiet klasi
Izveidojiet klasi un nosauciet to, kā vēlaties. Šajā rakstā tas tiks nosaukts
NetworkAppExample
publiskas klases NetworkAppExample {}
Solis 2. Izveidojiet galveno metodi
Izveidojiet galveno metodi un paziņojiet, ka tā var radīt izņēmumus
Izņēmums
veids un jebkura tā apakšklase - visi izņēmumi. Tā tiek uzskatīta par sliktu praksi, bet ir pieļaujama bezkaulu piemēriem.
publiskas klases NetworkAppExample {public static void main (String args) met izņēmums {}}
3. solis. Deklarējiet servera adresi
Šajā piemērā tiks izmantota vietējā resursdatora adrese un patvaļīgs porta numurs. Ostas numuram jābūt diapazonā no 0 līdz 65535 (ieskaitot). Tomēr portu numuri, no kuriem jāizvairās, svārstās no 0 līdz 1023 (ieskaitot), jo tie ir rezervēti sistēmas porti.
public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; }}
Solis 4. Izveidojiet serveri
Serveris ir saistīts ar adresi un portu un klausās ienākošos savienojumus. Java valodā
ServerSocket
attēlo servera puses galapunktu, un tā funkcija ir jaunu savienojumu pieņemšana.
ServerSocket
nav plūsmu datu lasīšanai un nosūtīšanai, jo tas neatspoguļo savienojumu starp serveri un klientu.
importēt java.net. InetAddress; importēt java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); }}
5. solis. Žurnāla servera izveide
Reģistrēšanas nolūkos drukājiet konsolē, ka serveris ir startēts.
importēt java.net. InetAddress; importēt java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); }}
6. solis. Izveidojiet klientu
Klients ir saistīts ar servera adresi un portu un pēc savienojuma izveidošanas klausās paketes (ziņas). Java valodā
Kontaktligzda
apzīmē vai nu klienta puses galapunktu, kas savienots ar serveri, vai savienojumu (no servera) ar klientu un tiek izmantots, lai sazinātos ar otru pusi.
importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); }}
7. solis. Reģistrēties savienojuma mēģinājumam
Reģistrēšanas nolūkos drukājiet konsolē, ka ir mēģināts izveidot savienojumu.
importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket serveris = new ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); }}
8. solis. Izveidojiet savienojumu
Klienti nekad nesavienosies, ja serveris neklausīsies un nepieņems, citiem vārdiem sakot, izveidos savienojumus. Java savienojumi tiek izveidoti, izmantojot
pieņemt ()
metode
ServerSocket
klase. Metode bloķēs izpildi, līdz klients izveidos savienojumu.
importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket serveris = new ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); }}
9. solis. Reģistrējiet izveidoto savienojumu
Reģistrācijas nolūkos izdrukājiet konsolē, ka ir izveidots savienojums starp serveri un klientu.
importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket serveris = new ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); }}
10. solis. Sagatavojiet sakaru plūsmas
Saziņa tiek veikta, izmantojot straumes, un šajā lietojumprogrammā neapstrādātas (savienojuma no) servera (ar klientu) un klienta plūsmas ir jāpiesaista datu vai objektu straumēm. Atcerieties, ka abām pusēm ir jāizmanto viens un tas pats straumes veids.
-
Datu plūsmas
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); }}
-
Objektu straumes
Ja tiek izmantotas vairākas objektu plūsmas, ievades plūsmas ir jāinicializē tādā pašā secībā kā izejas plūsmas, jo
ObjectOutputStream
nosūta galveni otrai pusei un
ObjectInputStream
bloķē izpildi, līdz tas nolasa galveni.
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); }}
Kārtību, kas norādīta iepriekšējā kodā, varētu būt vieglāk atcerēties - vispirms inicializējiet izejas straumes, pēc tam ievadiet straumes tādā pašā secībā. Tomēr vēl viens objektu plūsmu inicializācijas rīkojums ir šāds:
ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ());
11. solis. Pierakstieties, ka saziņa ir gatava
Reģistrēšanas nolūkos izdrukājiet konsolē, ka sakari ir gatavi.
// kods izlaists importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); // kods izlaists System.out.println ("Sakari ir gatavi."); }}
12. solis. Izveidojiet ziņu
Šajā pieteikumā
Sveika pasaule
teksts tiks nosūtīts uz serveri vai nu kā
baits
vai
Stīga
. Deklarējiet tāda veida mainīgo, kas ir atkarīgs no izmantotās straumes. Izmantot
baits
datu plūsmām un
Stīga
objektu plūsmām.
-
Datu plūsmas
Izmantojot datu plūsmas, serializācija tiek veikta, objektus pārvēršot primitīvos datu tipos vai
Stīga
. Šajā gadījumā,
Stīga
tiek pārveidots par
baits
rakstīšanas vietā
writeBytes ()
metode, lai parādītu, kā tas tiktu darīts ar citiem objektiem, piemēram, attēliem vai citiem failiem.
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket serveris = new ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); baits messageOut = "Sveika pasaule".getBytes (); }}
-
Objektu straumes
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket serveris = new ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); String messageOut = "Sveika pasaule"; }}
13. solis. Nosūtiet ziņu
Ierakstiet datus izvades plūsmā un izskalojiet straumi, lai pārliecinātos, ka dati ir pilnībā ierakstīti.
-
Datu plūsmas
Vispirms ir jānosūta ziņojuma garums, lai otra puse zinātu, cik baitu tai jālasa. Pēc tam, kad garums ir nosūtīts kā primitīvs vesels skaitlis, var nosūtīt baitus.
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); baits messageOut = "Sveika pasaule".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektu straumes
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); String messageOut = "Sveika pasaule"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Solis 14. Žurnāls nosūtīts ziņojums
Reģistrēšanas nolūkos izdrukājiet konsolē ziņojumu, kas ir nosūtīts.
-
Datu plūsmas
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); baits messageOut = "Sveika pasaule".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + jauna virkne (messageOut)); }}
-
Objektu straumes
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); String messageOut = "Sveika pasaule"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + messageOut); }}
Solis 15. Izlasiet ziņojumu
Lasiet datus no ievades straumes un konvertējiet tos. Tā kā mēs precīzi zinām nosūtīto datu veidu, mēs vai nu izveidosim
Stīga
no
baits
vai cast
Objekts
uz
Stīga
nepārbaudot, atkarībā no izmantotās straumes.
-
Datu plūsmas
Tā kā garums tika nosūtīts vispirms un baiti pēc tam, lasīšana jāveic tādā pašā secībā. Gadījumā, ja garums ir nulle, nav ko lasīt. Objekts tiek deserializēts, kad baiti tiek pārvērsti atpakaļ instancē, šajā gadījumā
Stīga
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); baits messageOut = "Sveika pasaule".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + jauna virkne (messageOut)); int garums = serverIn.readInt (); if (garums> 0) {baits messageIn = jauns baits [garums]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektu straumes
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); String messageOut = "Sveika pasaule"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + messageOut); String messageIn = (String) serverIn.readObject (); }}
16. solis. Žurnāla lasīšanas ziņojums
Reģistrācijas nolūkos izdrukājiet konsolē šo ziņojumu un izdrukājiet tā saturu.
-
Datu plūsmas
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); DataOutputStream clientOut = jauns DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = jauns DataInputStream (client.getInputStream ()); DataOutputStream serverOut = new DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = new DataInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); baits messageOut = "Sveika pasaule".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + jauna virkne (messageOut)); int garums = serverIn.readInt (); if (garums> 0) {baits messageIn = jauns baits [garums]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Ziņojums saņemts no klienta:" + jauna virkne (messageIn)); }}}
-
Objektu straumes
importēt java.io. ObjectInputStream; importēt java.io. ObjectOutputStream; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); ObjectOutputStream clientOut = jauns ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = jauns ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = jauns ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = jauns ObjectInputStream (connection.getInputStream ()); System.out.println ("Komunikācija ir gatava."); String messageOut = "Sveika pasaule"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Ziņojums nosūtīts serverim:" + messageOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Ziņojums saņemts no klienta:" + messageIn); }}
17. solis. Atvienojiet savienojumus
Savienojums tiek pārtraukts, kad viena puse aizver straumes. Java, aizverot izvades plūsmu, tiek slēgta arī saistītā ligzda un ievades plūsma. Kad puse no otras puses uzzina, ka savienojums ir miris, tai ir jāaizver arī izejas plūsma, lai novērstu atmiņas noplūdi.
// kods izlaists importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); // kods izlaists System.out.println ("Sakari ir gatavi."); // kods izlaists clientOut.close (); serverOut.close (); }}
18. solis. Žurnāla atvienošana
Reģistrēšanas nolūkos drukāšana konsoles savienojumos ir atvienota.
// kods izlaists importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); // kods izlaists System.out.println ("Sakari ir gatavi."); // kods izlaists clientOut.close (); serverOut.close (); System.out.println ("Savienojumi slēgti."); }}
19. darbība. Pārtraukt servera darbību
Savienojumi ir atvienoti, bet serveris joprojām darbojas un darbojas. Kā
ServerSocket
nav saistīta ar nevienu straumi, tā ir skaidri jāaizver, zvanot
aizvērt ()
metode.
// kods izlaists importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); // kods izlaists System.out.println ("Sakari ir gatavi."); // kods izlaists clientOut.close (); serverOut.close (); System.out.println ("Savienojumi slēgti."); server.close (); }}
20. solis. Žurnāla servera pārtraukšana
Reģistrēšanas nolūkos drukāšana konsoles serverī ir pārtraukta.
// kods izlaists importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. Socket; public class NetworkAppExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; ServerSocket server = jauna ServerSocket (ports, 50, InetAddress.getByName (resursdators)); System.out.println ("Serveris palaists."); Socket klients = new Socket (resursdators, ports); System.out.println ("Savienojuma izveide ar serveri …"); Kontaktligzdas savienojums = server.accept (); System.out.println ("Savienojums izveidots."); // kods izlaists System.out.println ("Sakari ir gatavi."); // kods izlaists clientOut.close (); serverOut.close (); System.out.println ("Savienojumi slēgti."); server.close (); System.out.println ("Serveris pārtraukts."); }}
21. solis. Apkopojiet un palaidiet
Reģistrēšana ļāva mums uzzināt, vai lietojumprogramma bija veiksmīga. Paredzamais iznākums:
Serveris palaists. Notiek savienojuma izveide ar serveri … Savienojums ir izveidots. Komunikācija ir gatava. Ziņojums nosūtīts uz serveri: Hello World Ziņojums saņemts no klienta: Hello World Connections ir slēgts. Serveris ir pārtraukts.
Ja jūsu iznākums nav tāds kā iepriekš, un tas, visticamāk, nenotiks, ir daži risinājumi:
-
Ja izeja apstājas pie līnijas
Savienojums izveidots.
un tiek izmantotas objektu plūsmas, noskalojiet katru
ObjectOutputStream
- tūlīt pēc inicializācijas, jo galvenes kāda iemesla dēļ netika nosūtītas.
-
Ja izdruka tiek izdrukāta
java.net. BindException: adrese jau tiek izmantota
- izvēlieties citu porta numuru, jo norādītais jau ir izmantots.
Padomi
- Savienojuma izveide ar cita tīkla serveri tiek veikta, izveidojot savienojumu ar tās ierīces ārējo IP adresi, kurā darbojas serveris ar pārsūtītu portu.
- Savienojuma izveide ar servera tajā pašā tīklā tiek veikta, vai nu izveidojot savienojumu ar tās ierīces privāto IP adresi, kurā darbojas serveris, vai pārsūtot portu un izveidojot savienojumu ar ierīces ārējo IP adresi.
- Ir programmatūra, piemēram, Hamachi, kas ļauj izveidot savienojumu ar serveri citā tīklā, nepārsūtot portu, taču ir nepieciešama programmatūras instalēšana abās ierīcēs.
Piemēri
Tīkla lietojumprogrammām, kas izmanto bloķējošu ievadi/izvadi, ir jāizmanto pavedieni. Šie piemēri parāda minimālu servera un klienta ieviešanu ar pavedieniem. Tīkla kods būtībā ir tāds pats kā rakstā, izņemot to, ka daži fragmenti tika sinhronizēti, pārvietoti uz pavedieniem un tiek apstrādāti izņēmumi.
Serveris.java
importēt java.io. IOException; importēt java.net. InetAddress; importēt java.net. ServerSocket; importēt java.net. SocketException; importēt java.net. UnknownHostException; importēt java.util. ArrayList; importēt java.util. Collections; importēt java.util. List; /*** Klase {@code Server} ir servera beigu punkts tīklā. {@code Server} pēc tam, kad ir piesaistīts noteiktai IP * adresei un portam, izveido savienojumus ar klientiem un spēj ar viņiem sazināties vai tos atvienot. *
* Šī klase ir droša pavedieniem. * * @versija 1.0 * @see Client * @see Connection */ public class Server realizē Runnable {private ServerSocket server; privāts saraksts
savienojumi; privāts pavedienu pavediens; privāts galīgais Objekta savienojumiLock = jauns objekts (); /** * Izveido {@code Server}, kas mijiedarbojas ar klientiem ar norādīto resursdatora nosaukumu un portu ar norādīto * pieprasīto maksimālo ienākošo klientu rindas garumu. * * @param resursdatora resursdatora adrese, ko izmantot. * @param ports Izmantojamais porta numurs. * @param kavēšanās Pieprasīts maksimālais ienākošo klientu rindas garums. * @throws NetworkException Ja, startējot serveri, rodas kļūda. */ publiskais serveris (virknes resursdators, int ports, int aizkavēšanās) izmet NetworkException {try {server = new ServerSocket (ports, atpalicība, InetAddress.getByName (resursdators)); } catch (UnknownHostException e) {mest jaunu NetworkException ("Saimnieka nosaukumu nevarēja atrisināt:" + resursdators, e); } catch (IllegalArgumentException e) {mest jaunu NetworkException ("Porta numuram jābūt no 0 līdz 65535 (ieskaitot):" + ports); } catch (IOException e) {mest jaunu NetworkException ("Serveri nevarēja palaist.", e); } savienojumi = Collections.synchronizedList (jauns ArrayList ()); pavediens = jauns pavediens (šis); pavediens.start (); } /*** Izveido {@code Server}, kas mijiedarbojas ar klientiem, izmantojot norādīto resursdatora nosaukumu un portu. * * @param saimniekdatora saistāmā resursdatora adrese. * @param ports Piesaistes porta numurs. * @throws NetworkException Ja, startējot serveri, rodas kļūdas. */ publiskais serveris (virknes resursdators, int ports) izmet NetworkException {šis (resursdators, ports, 50); } /*** Klausās, pieņem un reģistrē ienākošos savienojumus no klientiem. */ @Override public void run () {while (! Server.isClosed ()) {try {savienojumi.add (jauns savienojums (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Nosūta datus visiem reģistrētajiem klientiem. * * @param dati Nosūtāmie dati. * @throws IllegalStateException Ja dati tiek mēģināti rakstīt, kad serveris ir bezsaistē. * @throws IllegalArgumentException Ja nosūtāmie dati ir nulle. */ public void broadcast (Object data) {if (server.isClosed ()) {met jaunu IllegalStateException ("Dati nav nosūtīti, serveris ir bezsaistē."); } ja (dati == null) {mest jaunu IllegalArgumentException ("nulles dati"); } sinhronizēts (connectionLock) {for (Savienojuma savienojums: savienojumi) {try {connection.send (data); System.out.println ("Klientam veiksmīgi nosūtīti dati."); } catch (NetworkException e) {e.printStackTrace (); }}}} /*** Nosūta atvienošanas ziņojumu un atvieno norādīto klientu. * * @param savienojums Klients, lai atvienotu. * @throws NetworkException Ja savienojuma slēgšanas laikā rodas kļūda. */ public void atvienošana (Savienojuma savienojums) izmet NetworkException {if (connection.remove (connection)) {connection.close (); }} /*** Nosūta atvienošanas ziņojumu visiem klientiem, atvieno tos un pārtrauc servera darbību. */ public void close () izmet NetworkException {synchronized (connectionLock) {for (Savienojuma savienojums: savienojumi) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} savienojumi.skaidrs (); pamēģini {server.close (); } catch (IOException e) {mest jaunu NetworkException ("Kļūda, aizverot serveri."); } beidzot {thread.interrupt (); }} /*** Atgriež, vai serveris ir tiešsaistē. * * @return True, ja serveris ir tiešsaistē. Nepareizi, citādi. */ public Būla isOnline () {return! server.isClosed (); } /*** Atgriež reģistrētu klientu masīvu. */ publiskais savienojums getConnections () {sinhronizēts (savienojumiLock) {atgriešanās savienojumi.toArray (jauns savienojums [savienojumi.izmērs ()]); }}}
Klients.java
importēt java.io. IOException; importēt java.net. Socket; importēt java.net. UnknownHostException; /*** Klase {@code Client} attēlo klienta galapunktu tīklā. Kad pakalpojums {@code Client} ir izveidots savienojums ar noteiktu * serveri, tas var garantēt tikai saziņu ar serveri. Tas, vai citi klienti saņem datus *, ir atkarīgs no servera ieviešanas. *
* Šī klase ir droša pavedieniem. * * @version 1.0 * @see Server * @see Connection */ public class Client {privāts savienojuma savienojums; /*** Izveido {@code Client}, kas ir savienots ar serveri norādītajā resursdatorā un ostā. * * @param saimniekdatora saistāmā resursdatora adrese. * @param ports Piesaistes porta numurs. * @throws NetworkException Ja, startējot serveri, rodas kļūda. */ publiskais klients (virknes resursdators, int ports) izmet NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {mest jaunu NetworkException ("Saimnieka nosaukumu nevarēja atrisināt:" + resursdators, e); } catch (IllegalArgumentException e) {mest jaunu NetworkException ("Porta numuram jābūt no 0 līdz 65535 (ieskaitot):" + ports); } catch (IOException e) {mest jaunu NetworkException ("Serveri nevarēja palaist.", e); }} /*** Nosūta datus otrai pusei. * * @param dati Nosūtāmie dati. * @throws NetworkException Ja neizdodas rakstīt izvades straumē. * @throws IllegalStateException Ja dati tiek mēģināti rakstīt, kad savienojums ir slēgts. * @throws IllegalArgumentException Ja nosūtāmie dati ir nulle. * @throws UnsupportedOperationException Ja tiek mēģināts nosūtīt neatbalstītu datu tipu. */ public void send (Objekta dati) izmet NetworkException {connection.send (dati); } /*** Nosūta atvienošanas ziņojumu serverim un pārtrauc savienojumu ar to. */ public void close () izmet NetworkException {connection.close (); } /*** Atgriež, vai klients ir savienots ar serveri. * * @return True, ja klients ir pievienots. Nepareizi, citādi. */ public Būla isOnline () {return connection.isConnected (); } /*** Atgriež klienta gadījumu {@link Connection}. */ public Connection getConnection () {atgriešanās savienojums; }}
Savienojums.java
importēt java.io. DataInputStream; importēt java.io. DataOutputStream; importēt java.io. IOException; importēt java.net. Socket; importēt java.net. SocketException; /** * Klase {@code Connection} attēlo vai nu savienojumu no servera uz klientu, vai klienta galapunktu tīklā * {@code Connection} pēc savienojuma izveidošanas var apmainīties ar datiem ar citām pusēm vai pusēm, atkarībā no tā uz servera * ieviešanu. *
* Šī klase ir droša pavedieniem. * * @versija 1.0 * @see Server * @see Client */ publiskās klases Savienojums īsteno Runnable {private Socket socket; privāta DataOutputStream out; privāta DataInputStream in; privāts pavedienu pavediens; private final Object writeLock = jauns objekts (); private final Object readLock = jauns objekts (); /*** Izveido {@code Connection}, izmantojot noteiktas {@link Socket} straumes. * * @param ligzda ligzda, no kuras var iegūt straumes.*/ public Connection (Socket socket) izmet NetworkException {if (socket == null) {met jaunu IllegalArgumentException ("null socket"); } this.socket = ligzda; try {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {mest jaunu NetworkException ("Nevarēja piekļūt izejas straumei.", e); } try {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {mest jaunu NetworkException ("Nevarēja piekļūt ievades straumei.", e); } pavediens = jauns pavediens (šis); pavediens.start (); } /*** Izlasa ziņojumus, kamēr ir izveidots savienojums ar otru pusi. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; baits baiti; sinhronizēts (readLock) {identifikators = in.readInt (); int garums = in.readInt (); ja (garums> 0) {baiti = jauns baits [garums]; in.readFully (baiti, 0, baiti.garums); } cits {turpināt; }} slēdzis (identifikators) {case Identifier. INTERNAL: String komanda = new String (baiti); if (command.equals ("atvienot")) {ja (! socket.isClosed ()) {System.out.println ("Saņemta atvienošanas pakete."); mēģināt {aizvērt (); } nozveja (NetworkException e) {return; }}} pārtraukums; gadījuma identifikators. TEKSTS: System.out.println ("Ziņojums saņemts:" + jauna virkne (baiti)); pārtraukums; noklusējums: System.out.println ("Saņemti neatpazītie dati."); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} nozveja (IOException e) {e.printStackTrace (); }}} /*** Nosūta datus otrai pusei. * * @param dati Nosūtāmie dati. * @throws NetworkException Ja neizdodas rakstīt izvades straumē. * @throws IllegalStateException Ja dati tiek mēģināti rakstīt, kad savienojums ir slēgts. * @throws IllegalArgumentException Ja nosūtāmie dati ir nulle. * @throws UnsupportedOperationException Ja tiek mēģināts nosūtīt neatbalstītu datu tipu. */ public void send (Objekta dati) met NetworkException {if (socket.isClosed ()) {met jaunu IllegalStateException ("Dati nav nosūtīti, savienojums ir slēgts."); } ja (dati == null) {mest jaunu IllegalArgumentException ("nulles dati"); } int identifikators; baits baiti; if (string instance) {identifier = Identifier. TEXT; baiti = ((String) dati).getBytes (); } else {met jaunu UnsupportedOperationException ("Neatbalstīts datu tips:" + data.getClass ()); } mēģināt {synchronized (writeLock) {out.writeInt (identifikators); out.writeInt (baiti.garums); out.write (baiti); out.flush (); }} catch (IOException e) {mest jaunu NetworkException ("Datus nevarēja nosūtīt.", e); }} /*** Nosūta atvienošanas ziņojumu otrai pusei un pārtrauc savienojumu ar to. */ public void close () met NetworkException {if (socket.isClosed ()) {met jaunu IllegalStateException ("Savienojums jau ir slēgts."); } mēģiniet {baits ziņojums = "atvienot".getBytes (); sinhronizēts (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (ziņojuma garums); out.write (ziņa); out.flush (); }} catch (IOException e) {System.out.println ("Atvienošanas ziņojumu nevarēja nosūtīt."); } mēģināt {synchronized (writeLock) {out.close (); }} catch (IOException e) {mest jaunu NetworkException ("Kļūda, slēdzot savienojumu.", e); } beidzot {thread.interrupt (); }} /*** Atgriež, vai savienojums ar otru pusi ir dzīvs. * * @return Patiess, ja savienojums ir dzīvs. Nepareizi, citādi. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifier.java
/** * Klasē {@code Identifier} ir konstantas, ko {@link Connection} izmanto, lai sērijveidotu un deserializētu tīklā nosūtītos datus *. * * @version 1.0 * @see Connection * / public final class Identifier { / ** * Identifikators iekšējiem ziņojumiem. */ public static final int INTERNAL = 1; /*** Teksta ziņojumu identifikators. */ public static final int TEXT = 2; }
NetworkException.java
/*** Klase {@code NetworkException} norāda ar tīklu saistītu kļūdu. * / public class NetworkException paplašina izņēmumu { / *** Izveido {@code NetworkException}, kura ziņojums ir {@code null}. * / public NetworkException () {} / *** Izveido {@code NetworkException} ar norādīto ziņojumu. * * @param message Ziņojums, kas apraksta kļūdu. */ public NetworkException (String message) {super (ziņojums); } /*** Izveido {@code NetworkException} ar norādīto ziņojumu un cēloni. * * @param message Ziņojums, kas apraksta kļūdu. * @param cēlonis Kļūdas cēlonis. */ public NetworkException (String message, Throwable cause) {super (ziņojums, cēlonis); } /*** Izveido {@code NetworkException} ar norādītu iemeslu. * * @param cēlonis Kļūdas cēlonis. */ public NetworkException (Throwable cēlonis) {super (cēlonis); }}
LietošanaPiemērs.java
/*** Klase {@code UsageExample} parāda {@link Server} un {@link Client} lietojumu. Šajā piemērā tiek izmantots * {@link Thread#miega režīms (garš)}, lai nodrošinātu katra segmenta izpildi, jo ātra sākšana un aizvēršana neļauj izpildīt dažus * segmentus. * * @versija 1.0 * @see Server * @see Client */ public class UsageExample {public static void main (String args) met Izņēmums {String host = "localhost"; int osta = 10430; Servera serveris = jauns serveris (resursdators, ports); Klienta klients = jauns klients (resursdators, ports); Vītne.miega (100L); client.send ("Labdien!"); server.broadcast ("Hei, puisis!"); Vītne.miega (100L); server.disconnect (server.getConnections () [0]); // vai client.close (), lai atvienotos no klienta puses server.close (); }}