Kodo, kuris vykdomas tam tikrame įrenginyje, rašymas yra labai patenkintas. Tačiau rašyti kodą, kuris vykdomas keliuose tarpusavyje bendraujančiuose įrenginiuose, tiesiog patvirtina gyvybė. Šis straipsnis išmokys jus prisijungti ir keistis pranešimais tinkle naudojant perdavimo valdymo protokolą (TCP).
Šiame straipsnyje jūs sukursite programą, kuri prijungs jūsų kompiuterį prie savęs ir iš esmės padarys jį beprotišką - kalbėkite su savimi. Taip pat sužinosite skirtumą tarp dviejų plačiausiai naudojamų „Java“tinklų kūrimo srautų ir jų veikimo.
Duomenų ir objektų srautai
Prieš pasineriant į kodą, reikia atskirti dviejų straipsnyje naudojamų srautų skirtumą.
Duomenų srautai
Duomenų srautai apdoroja primityvius duomenų tipus ir eilutes. Duomenų srautais siunčiami duomenys turi būti rankiniu būdu sugrupuoti ir deserializuoti, o tai apsunkina sudėtingų duomenų perdavimą. Tačiau duomenų srautai gali bendrauti su serveriais ir klientais, parašytais kitomis kalbomis nei „Java“. Neapdoroti srautai šiuo aspektu yra panašūs į duomenų srautus, tačiau duomenų srautai užtikrina, kad duomenys būtų suformatuoti nepriklausomai nuo platformos, o tai naudinga, nes abi šalys galės skaityti išsiųstus duomenis.
Objektų srautai
Objektų srautai apdoroja primityvius duomenų tipus ir įgyvendinamus objektus
Serijuojama
sąsaja. Duomenys, siunčiami per objektų srautus, automatiškai serijuojami ir deserializuojami, todėl lengviau perkelti sudėtingus duomenis. Tačiau objektų srautai gali bendrauti tik su serveriais ir klientais, parašytais „Java“. Taip pat,
ObjectOutputStream
inicijuojant, siunčia antraštę į
„InputStream“
kitos šalies, kuri inicijuodama blokuoja vykdymą, kol bus gauta antraštė.
Žingsniai
Žingsnis 1. Sukurkite klasę
Sukurkite klasę ir pavadinkite ją taip, kaip norite. Šiame straipsnyje jis bus pavadintas
„NetworkAppExample“
viešosios klasės „NetworkAppExample“{}
Žingsnis 2. Sukurkite pagrindinį metodą
Sukurkite pagrindinį metodą ir paskelbkite, kad jis gali sukelti išimčių
Išimtis
tipas ir bet kuris jo poklasis - visos išimtys. Tai laikoma bloga praktika, tačiau yra priimtina pavyzdžiams be kaulo.
viešosios klasės „NetworkAppExample“{public static void main (String args) metimai Išimtis {}}
Žingsnis 3. Deklaruokite serverio adresą
Šiame pavyzdyje bus naudojamas vietinio kompiuterio adresas ir savavališkas prievado numeris. Prievado numeris turi būti nuo 0 iki 65535 (imtinai). Tačiau vengiamų prievadų numeriai yra nuo 0 iki 1023 (imtinai), nes jie yra rezervuoti sistemos prievadai.
public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; }}
Žingsnis 4. Sukurkite serverį
Serveris yra susietas su adresu ir prievadu ir klauso gaunamų ryšių. „Java“,
ServerSocket
žymi serverio pusės galinį tašką ir jo funkcija yra priimti naujus ryšius.
ServerSocket
neturi srautų duomenims skaityti ir siųsti, nes neatspindi ryšio tarp serverio ir kliento.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); }}
Žingsnis 5. Žurnalo serverio pradžia
Registravimo tikslais spausdinkite į konsolę, kuriame buvo paleistas serveris.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); }}
Žingsnis 6. Sukurkite klientą
Klientas yra susietas su serverio adresu ir prievadu ir užmezgęs ryšį klausosi paketų (pranešimų). „Java“,
Lizdas
reiškia arba kliento pusės galinį tašką, prijungtą prie serverio, arba ryšį (iš serverio) su klientu ir yra naudojamas bendrauti su kita puse.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); }}
Žingsnis 7. Prisijungimo bandymas
Registravimo tikslais spausdinkite į konsolę, kad buvo bandoma prisijungti.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); }}
Žingsnis 8. Užmegzkite ryšį
Klientai niekada neprisijungs, nebent serveris klausys ir nepriims, kitaip tariant, nenustatys ryšių. „Java“ryšiai užmezgami naudojant
priimti()
metodas
ServerSocket
klasė. Metodas blokuoja vykdymą, kol klientas prisijungs.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); }}
Žingsnis 9. Prisijunkite prie užmegzto ryšio
Registravimo tikslais į konsolę atspausdinkite, kad užmegztas ryšys tarp serverio ir kliento.
importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); }}
Žingsnis 10. Paruoškite bendravimo srautus
Ryšys vyksta srautais, o šioje programoje neapdoroti (ryšio iš) serverio (su klientu) ir kliento srautai turi būti susieti su duomenų arba objektų srautais. Atminkite, kad abi šalys turi naudoti tą patį srauto tipą.
-
Duomenų srautai
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); }}
-
Objektų srautai
Kai naudojami keli objektų srautai, įvesties srautai turi būti inicijuojami ta pačia tvarka kaip ir išvesties srautai, nes
ObjectOutputStream
siunčia antraštę kitai šaliai ir
ObjectInputStream
blokuoja vykdymą, kol nuskaito antraštę.
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); }}
Užsakymą, kaip nurodyta aukščiau esančiame kode, gali būti lengviau įsiminti - pirmiausia inicijuokite išvesties srautus, tada įveskite srautus ta pačia tvarka. Tačiau kita objektų srautų inicijavimo tvarka yra tokia:
ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ());
Žingsnis 11. Prisijunkite, kad ryšys paruoštas
Registravimo tikslais spausdinkite į konsolę, kad ryšys paruoštas.
// kodas praleistas importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); // kodas praleistas System.out.println ("Ryšys paruoštas."); }}
Žingsnis 12. Sukurkite pranešimą
Šioje programoje
Labas pasauli
tekstas bus siunčiamas į serverį arba
baitas
arba
Styginė
. Paskelbkite tokio tipo kintamąjį, kuris priklauso nuo naudojamo srauto. Naudoti
baitas
duomenų srautams ir
Styginė
objektų srautams.
-
Duomenų srautai
Naudojant duomenų srautus, serializacija atliekama konvertuojant objektus į primityvius duomenų tipus arba
Styginė
. Tokiu atveju,
Styginė
yra konvertuojamas į
baitas
vietoj rašymo
writeBytes ()
metodas, parodantis, kaip tai būtų daroma su kitais objektais, pvz., vaizdais ar kitais failais.
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); baitas messageOut = "Labas pasaulis".getBytes (); }}
-
Objektų srautai
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); String messageOut = "Labas pasaulis"; }}
Žingsnis 13. Siųskite pranešimą
Įrašykite duomenis į išvesties srautą ir praplaukite srautą, kad įsitikintumėte, jog duomenys buvo visiškai parašyti.
-
Duomenų srautai
Pirmiausia reikia išsiųsti pranešimo ilgį, kad kita šalis žinotų, kiek baitų reikia perskaityti. Kai ilgis siunčiamas kaip primityvus sveikasis skaičius, galima siųsti baitus.
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); baitas messageOut = "Labas pasaulis".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektų srautai
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); String messageOut = "Labas pasaulis"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Žingsnis 14. Žurnalas išsiųstas pranešimas
Registravimo tikslais spausdinkite į konsolę, kad pranešimas buvo išsiųstas.
-
Duomenų srautai
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas jungtis = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); baitas messageOut = "Labas pasaulis".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + nauja eilutė (messageOut)); }}
-
Objektų srautai
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); String messageOut = "Labas pasaulis"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + messageOut); }}
Žingsnis 15. Perskaitykite pranešimą
Skaitykite duomenis iš įvesties srauto ir konvertuokite juos. Kadangi tiksliai žinome siunčiamų duomenų tipą, mes arba sukursime
Styginė
nuo
baitas
arba mesti
Objektas
į
Styginė
nepatikrinus, priklausomai nuo naudojamo srauto.
-
Duomenų srautai
Kadangi ilgis buvo išsiųstas pirmiausia, o vėliau baitai, skaitymas turi būti atliekamas ta pačia tvarka. Jei ilgis lygus nuliui, nėra ko skaityti. Objektas deserializuojamas, kai baitai vėl paverčiami egzemplioriumi, šiuo atveju
Styginė
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); baitas messageOut = "Labas pasaulis".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + nauja eilutė (messageOut)); int ilgis = serverIn.readInt (); if (ilgis> 0) {baitas messageIn = naujas baitas [ilgis]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektų srautai
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); String messageOut = "Labas pasaulis"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + messageOut); String messageIn = (String) serverIn.readObject (); }}
Žingsnis 16. Prisijunkite prie perskaityto pranešimo
Registravimo tikslais spausdinkite konsolėje tą pranešimą ir gaukite jo turinį.
-
Duomenų srautai
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); DataOutputStream clientOut = naujas DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = naujas DataInputStream (client.getInputStream ()); DataOutputStream serverOut = naujas DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = naujas DataInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); baitas messageOut = "Labas pasaulis".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + nauja eilutė (messageOut)); int ilgis = serverIn.readInt (); if (ilgis> 0) {baitas messageIn = naujas baitas [ilgis]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Pranešimas gautas iš kliento:" + nauja eilutė (messageIn)); }}}
-
Objektų srautai
importuoti java.io. ObjectInputStream; importuoti java.io. ObjectOutputStream; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); ObjectOutputStream clientOut = naujas ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = naujas ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = naujas ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = naujas ObjectInputStream (connection.getInputStream ()); System.out.println („Ryšys paruoštas“); String messageOut = "Labas pasaulis"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Pranešimas išsiųstas į serverį:" + messageOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Pranešimas gautas iš kliento:" + messageIn); }}
Žingsnis 17. Atjunkite jungtis
Ryšys nutrūksta, kai viena šalis uždaro savo srautus. „Java“, uždarius išvesties srautą, taip pat uždaromi susiję lizdai ir įvesties srautai. Kai kita pusė sužino, kad ryšys nutrūko, ji taip pat turi uždaryti išvesties srautą, kad būtų išvengta atminties nutekėjimo.
// kodas praleistas importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); // kodas praleistas System.out.println ("Ryšys paruoštas."); // kodas praleistas clientOut.close (); serverOut.close (); }}
Žingsnis 18. Rąstų atjungimas
Registravimo tikslais spausdinimas prie konsolės buvo atjungtas.
// kodas praleistas importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); // kodas praleistas System.out.println ("Ryšys paruoštas."); // kodas praleistas clientOut.close (); serverOut.close (); System.out.println („Ryšiai uždaryti“); }}
Žingsnis 19. Išjunkite serverį
Ryšiai atjungti, bet serveris vis dar veikia. Kaip
ServerSocket
nėra susietas su jokiu srautu, jį reikia aiškiai uždaryti skambinant
Uždaryti()
metodas.
// kodas praleistas importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); // kodas praleistas System.out.println ("Ryšys paruoštas."); // kodas praleistas clientOut.close (); serverOut.close (); System.out.println („Ryšiai uždaryti“); server.close (); }}
Žingsnis 20. Prisijungti prie serverio nutraukimo
Registravimo tikslais spausdinimas į konsolės serverį buvo nutrauktas.
// kodas praleistas importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. Socket; public class NetworkAppExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; ServerSocket serveris = naujas ServerSocket (prievadas, 50, InetAddress.getByName (priegloba)); System.out.println („Serveris paleistas“); Lizdo klientas = naujas lizdas (priegloba, prievadas); System.out.println („Prisijungimas prie serverio …“); Lizdas ryšys = server.accept (); System.out.println („Ryšys užmegztas“); // kodas praleistas System.out.println ("Ryšys paruoštas."); // kodas praleistas clientOut.close (); serverOut.close (); System.out.println („Ryšiai uždaryti“); server.close (); System.out.println („Serveris nutrauktas“); }}
21 žingsnis. Sudarykite ir paleiskite
Prisijungimas leido mums sužinoti, ar programa buvo sėkminga, ar ne. Numatoma išvestis:
Serveris paleistas. Prisijungiama prie serverio… Ryšys užmegztas. Bendravimas yra paruoštas. Pranešimas išsiųstas į serverį: „Hello World“Pranešimas gautas iš kliento: „Hello World Connections“uždarytas. Serveris nutrauktas.
Jei jūsų produkcija nėra tokia, kaip nurodyta aukščiau, ir mažai tikėtina, kad tai atsitiks, yra keletas sprendimų:
-
Jei išėjimas sustoja ties linija
Ryšys užmegztas.
ir objektų srautai, praplaukite kiekvieną
ObjectOutputStream
- iškart po inicijavimo, nes antraštės dėl tam tikrų priežasčių nebuvo išsiųstos.
-
Jei išvestis spausdinama
java.net. BindException: adresas jau naudojamas
- pasirinkite kitą prievado numerį, nes nurodytasis jau naudojamas.
Patarimai
- Prisijungimas prie serverio kitame tinkle atliekamas prisijungus prie išorinio IP adreso įrenginyje, kuriame veikia serveris, turintis persiunčiamą prievadą.
- Prisijungimas prie serverio tame pačiame tinkle atliekamas prisijungiant prie įrenginio, kuriame veikia serveris, privataus IP adreso arba persiunčiant prievadą ir prisijungiant prie išorinio įrenginio IP adreso.
- Yra programinės įrangos, pvz., „Hamachi“, kuri leidžia prisijungti prie serverio kitame tinkle nepersiunčiant prievado, tačiau tam reikia įdiegti programinę įrangą abiejuose įrenginiuose.
Pavyzdžiai
Tinklo programoms, kurios naudoja blokuojančią įvestį/išvestį, reikia naudoti gijas. Šie pavyzdžiai rodo minimalistinį serverio ir kliento įgyvendinimą su gijomis. Tinklo kodas iš esmės yra toks pat kaip straipsnyje, išskyrus tai, kad kai kurie fragmentai buvo sinchronizuoti, perkelti į gijas ir tvarkomi išimtys.
Serveris.java
importuoti java.io. IOException; importuoti java.net. InetAddress; importuoti java.net. ServerSocket; importuoti java.net. SocketException; importuoti java.net. UnknownHostException; importuoti java.util. ArrayList; importuoti java.util. Collections; importuoti java.util. List; /*** Klasė {@code Server} yra serverio galinis taškas tinkle. {@code Server}, susietas su tam tikru IP * adresu ir prievadu, užmezga ryšius su klientais ir gali su jais bendrauti arba juos atjungti. *
* Ši klasė yra saugi. * * @version 1.0 * @see Client * @see Connection */ public class Server realizuoja Runnable {private ServerSocket server; privatus sąrašas
jungtys; privatus siūlų siūlas; privatus galutinis Objekto ryšiaiLock = naujas objektas (); /** * Sukuria {@code Server}, kuris sąveikauja su klientais pagal nurodytą pagrindinio kompiuterio pavadinimą ir prievadą su nurodytu * prašomu maksimaliu įeinančių klientų eilės ilgiu. * * @param pagrindinio kompiuterio pagrindinio kompiuterio adresas, kurį reikia naudoti. * @param prievadas Naudojamas prievado numeris. * @param atsilikimas Prašoma maksimalaus įeinančių klientų eilės ilgio. * @throws NetworkException Jei paleidžiant serverį įvyksta klaida. */ viešasis serveris (eilutės priegloba, int prievadas, int atsilikimas) meta NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throws new NetworkException ("Pagrindinio kompiuterio pavadinimo nepavyko išspręsti:" + priegloba, e); } catch (IllegalArgumentException e) {throws new NetworkException ("Prievado numeris turi būti nuo 0 iki 65535 (imtinai):" + prievadas); } catch (IOException e) {throws new NetworkException ("Nepavyko paleisti serverio.", e); } jungtys = Collections.synchronizedList (naujas ArrayList ()); siūlas = naujas Siūlas (šis); thread.start (); } /*** Sukuria {@code Server}, kuris sąveikauja su klientais pagal nurodytą pagrindinio kompiuterio pavadinimą ir prievadą. * * @param pagrindinio kompiuterio prieglobos adresas, kurį reikia susieti. * @param prievadas Prijungti prievado numerį. * @throws NetworkException Jei paleidžiant serverį atsiranda klaidų. */ viešasis serveris (eilutės priegloba, int prievadas) meta „NetworkException“{tai (priegloba, prievadas, 50); } /*** Klausosi, priima ir registruoja gaunamus klientų ryšius. */ @Override public void run () {while (! Server.isClosed ()) {try {connection.add (new Connection (server.accept ()))); } catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Siunčia duomenis visiems registruotiems klientams. * * @param data Duomenys, kuriuos reikia siųsti. * @throws IllegalStateException Jei bandoma rašyti duomenis, kai serveris neprisijungęs. * @throws IllegalArgumentException Jei siunčiami duomenys yra niekiniai. */ public void broadcast (Objekto duomenys) {if (server.isClosed ()) {thro new new IllegalStateException ("Duomenys nesiųsti, serveris neprisijungęs."); } if (duomenys == null) {išmesti naują IllegalArgumentException ("null data"); } sinchronizuotas (connectionLock) {for (Ryšio ryšys: ryšiai) {try {connection.send (data); System.out.println („Duomenys sėkmingai išsiųsti klientui“); } sugauti (NetworkException e) {e.printStackTrace (); }}}} /*** Siunčia atsijungimo pranešimą ir atjungia nurodytą klientą. * * @param ryšys Klientas, kurį reikia atjungti. * @throws NetworkException Jei uždarant ryšį įvyksta klaida. */ public void disconnect (Connection connection) meta NetworkException {if (connection.remove (connection)) {connection.close (); }} /*** Siunčia atjungimo pranešimą visiems klientams, atjungia juos ir nutraukia serverį. */ public void close () meta „NetworkException“{synchronized (connectionLock) {for (Ryšio ryšys: ryšiai) {try {connection.close (); } sugauti (NetworkException e) {e.printStackTrace (); }}} jungtys. aiškus (); pabandyk {server.close (); } catch (IOException e) {throws new NetworkException ("Klaida uždarant serverį."); } pagaliau {thread.interrupt (); }} /*** Grąžina, ar serveris yra prisijungęs, ar ne. * * @return Tiesa, jei serveris yra prisijungęs. Klaidinga, kitaip. */ public boolean isOnline () {return! server.isClosed (); } /*** Pateikia registruotų klientų masyvą. */ public Connection getConnections () {synchronized (connectionLock) {return connection.toArray (new Connection [connection.size ()]); }}}
Klientas.java
importuoti java.io. IOException; importuoti java.net. Socket; importuoti java.net. UnknownHostException; /*** Klasė {@code Client} reiškia kliento galutinį tašką tinkle. {@code Client}, prisijungus prie tam tikro * serverio, garantuoja, kad galės bendrauti tik su serveriu. Ar kiti klientai gaus duomenis *, priklauso nuo serverio diegimo. *
* Ši klasė yra saugi. * * @version 1.0 * @see Server * @see Connection */ public class Client {private Connection connection; /*** Sukuria {@code Client}, prijungtą prie serverio nurodytame priegloboje ir prievade. * * @param pagrindinio kompiuterio prieglobos adresas, kurį reikia susieti. * @param prievadas Prijungti prievado numerį. * @throws NetworkException Jei paleidžiant serverį įvyksta klaida. */ public Client (String host, int port) meta NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throws new NetworkException ("Pagrindinio kompiuterio pavadinimo nepavyko išspręsti:" + priegloba, e); } catch (IllegalArgumentException e) {throws new NetworkException ("Prievado numeris turi būti nuo 0 iki 65535 (imtinai):" + prievadas); } catch (IOException e) {throws new NetworkException ("Nepavyko paleisti serverio.", e); }} /*** Siunčia duomenis kitai šaliai. * * @param data Duomenys, kuriuos reikia siųsti. * @throws NetworkException Jei nepavyksta rašyti į išvesties srautą. * @throws IllegalStateException Jei bandoma įrašyti duomenis, kai ryšys uždarytas. * @throws IllegalArgumentException Jei siunčiami duomenys yra niekiniai. * @throws UnsupportedOperationException Jei bandoma siųsti nepalaikomą duomenų tipą. */ public void send (Objekto duomenys) meta NetworkException {connection.send (duomenys); } /*** Siunčia atjungimo pranešimą serveriui ir nutraukia ryšį su juo. */ public void close () meta NetworkException {connection.close (); } /*** Grąžina, ar klientas yra prijungtas prie serverio. * * @return Tiesa, jei klientas prijungtas. Klaidinga, kitaip. */ public boolean isOnline () {return connection.isConnected (); } /*** Grąžina kliento {@link Connection} egzempliorių. */ public Connection getConnection () {return connection; }}
Ryšys.java
importuoti java.io. DataInputStream; importuoti java.io. DataOutputStream; importuoti java.io. IOException; importuoti java.net. Socket; importuoti java.net. SocketException; /** * Klasė {@code Connection} reiškia ryšį iš serverio į klientą arba kliento galutinį tašką tinkle * {@code Connection}, prisijungęs, gali keistis duomenimis su kita šalimi ar šalimis, priklausomai nuo serveryje * diegimas. *
* Ši klasė yra saugi. * * @version 1.0 * @see Server * @see Client */ public class Connection implements Runnable {private Socket socket; privati „DataOutputStream“; privatus „DataInputStream“; privatus siūlų siūlas; private final Object writeLock = naujas objektas (); private final Object readLock = naujas objektas (); /*** Sukuria {@code Connection} naudodami nurodyto {@link Socket} srautus. * * @param lizdas, skirtas srautams gauti.*/ viešasis ryšys (lizdo lizdas) meta „NetworkException“{if (socket == null) {metimas naujas „IllegalArgumentException“(„null socket“); } this.socket = lizdas; try {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throws new NetworkException ("Nepavyko pasiekti išvesties srauto.", e); } try {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throws new NetworkException ("Nepavyko pasiekti įvesties srauto.", e); } thread = new Thread (tai); thread.start (); } /*** Skaito pranešimus, kol ryšys su kita šalimi gyvas. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; baitų baitų; sinchronizuotas (readLock) {identifikatorius = in.readInt (); int ilgis = in.readInt (); if (ilgis> 0) {baitai = naujas baitas [ilgis]; in.readFully (baitai, 0, baitai.ilgis); } else {tęsti; }} jungiklis (identifikatorius) {case Identifier. INTERNAL: String komanda = new String (baitai); if (command.equals ("atsijungti")) {if (! socket.isClosed ()) {System.out.println ("Gautas atjungimo paketas."); pabandyti {uždaryti (); } pagauti (NetworkException e) {return; } } } pertrauka; atvejo identifikatorius. TEKSTAS: System.out.println ("Pranešimas gautas:" + nauja eilutė (baitai)); pertrauka; numatytasis: System.out.println („Gauti neatpažinti duomenys“); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} laimikis (IOException e) {e.printStackTrace (); }}} /*** Siunčia duomenis kitai šaliai. * * @param data Duomenys, kuriuos reikia siųsti. * @throws NetworkException Jei nepavyksta rašyti į išvesties srautą. * @throws IllegalStateException Jei bandoma įrašyti duomenis, kai ryšys uždarytas. * @throws IllegalArgumentException Jei siunčiami duomenys yra niekiniai. * @throws UnsupportedOperationException Jei bandoma siųsti nepalaikomą duomenų tipą. */ public void send (Objekto duomenys) meta „NetworkException“{if (socket.isClosed ()) {metimas naujas „IllegalStateException“(„Duomenys nesiųsti, ryšys uždarytas“); } if (duomenys == null) {išmesti naują IllegalArgumentException ("null data"); } int identifikatorius; baitų baitų; if (eilutės duomenų egzempliorius) {identifier = Identifier. TEXT; baitai = ((eilutės) duomenys).getBytes (); } else {mesti naują UnsupportedOperationException ("Nepalaikomas duomenų tipas:" + data.getClass ()); } pabandyti {synchronized (writeLock) {out.writeInt (identifikatorius); out.writeInt (baitai.ilgis); out.write (baitai); out.flush (); }} catch (IOException e) {throws new NetworkException ("Duomenų nepavyko išsiųsti.", e); }} /*** Siunčia atsijungimo pranešimą kitai šaliai ir nutraukia ryšį. */ public void close () meta „NetworkException“{if (socket.isClosed ()) {mesti naują „IllegalStateException“(„Ryšys jau uždarytas“); } pabandykite {baitas pranešimas = "atjungti".getBytes (); sinchronizuotas (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (message.length); out.write (žinutė); out.flush (); }} catch (IOException e) {System.out.println ("Nepavyko išsiųsti atsijungimo pranešimo."); } pabandyti {synchronized (writeLock) {out.close (); }} catch (IOException e) {throws new NetworkException ("Klaida uždarant ryšį.", e); } pagaliau {thread.interrupt (); }} /*** Grąžina, ar ryšys su kita šalimi yra gyvas. * * @return Tiesa, jei ryšys gyvas. Klaidinga, kitaip. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifier.java
/** * Klasėje {@code Identifier} yra konstantos, kurias {@link Connection} naudoja tinklu siunčiamų duomenų * serijizavimui ir deserializavimui. * * @version 1.0 * @see Connection * / public final class Identifier { / ** * Vidinių pranešimų identifikatorius. */ public static final int INTERNAL = 1; /*** Tekstinių pranešimų identifikatorius. */ public static final int TEXT = 2; }
NetworkException.java
/*** Klasė {@code NetworkException} nurodo su tinklu susijusią klaidą. * / public class NetworkException pratęsia išimtį { / *** Sukuria {@code NetworkException}, kurio pranešimas yra {@code null}. * / public NetworkException () {} / *** Sukuria {@code NetworkException} su nurodytu pranešimu. * * @param message Pranešimas klaidai apibūdinti. */ public NetworkException (String message) {super (pranešimas); } /*** Sukuria {@code NetworkException} su nurodytu pranešimu ir priežastimi. * * @param message Pranešimas klaidai apibūdinti. * @param priežastis Klaidos priežastis. */ public NetworkException (String message, Throwable reason) {super (pranešimas, priežastis); } /*** Sukuria {@code NetworkException} dėl nurodytos priežasties. * * @param priežastis Klaidos priežastis. */ public NetworkException (Throwable cause) {super (priežastis); }}
NaudojimasPavyzdys.java
/*** Klasėje {@code UsageExample} rodomas {@link Server} ir {@link Client} naudojimas. Šiame pavyzdyje naudojamas * {@link Thread#sleep (ilgas)}, siekiant užtikrinti, kad kiekvienas segmentas būtų įvykdytas, nes dėl greito paleidimo ir uždarymo kai kurie * segmentai nevykdomi. * * @version 1.0 * @see Server * @see Client */ public class UsageExample {public static void main (String args) metimai Išimtis {String host = "localhost"; int prievadas = 10430; Serverio serveris = naujas serveris (priegloba, prievadas); Kliento klientas = naujas klientas (priegloba, prievadas); Siūlai.miegoti (100L); client.send („Labas“); server.broadcast ("Ei, vaikeli!"); Siūlai.miegoti (100L); server.disconnect (server.getConnections () [0]); // arba client.close () atsijungti nuo kliento pusės server.close (); }}