java.io
pakete un NIO, nebloķējošais I / O (java.nio
) API, kas ieviesti Java 1.4. Visbeidzot, NIO.2 jūs redzēsit piemēru, kas parāda Java tīklošanu, kas ieviesta no Java 7 uz priekšu.Socket programmēšana ir saistīta ar divām sistēmām, kas savstarpēji sazinās. Parasti tīkla komunikācijai ir divas garšas: Transporta vadības protokols (TCP) un Lietotāju datagrammas protokols (UDP). TCP un UDP tiek izmantoti dažādiem mērķiem, un abiem ir unikāli ierobežojumi:
- TCP ir salīdzinoši vienkāršs un uzticams protokols, kas ļauj klientam izveidot savienojumu ar serveri un abām sistēmām sazināties. TCP gadījumā katra entītija zina, ka ir saņemtas tās komunikācijas lietderīgās slodzes.
- UDP ir a bezsaistes protokols un tas ir piemērots scenārijiem, kur, lai sasniegtu galamērķi, nav obligāti vajadzīga katra pakete, piemēram, multivides straumēšanai.
Lai novērtētu atšķirību starp TCP un UDP, apsveriet, kas notiktu, ja straumētu video no savas iecienītās vietnes un tas nomestu rāmjus. Vai vēlaties, lai klients palēnina filmas uzņemšanu, lai saņemtu trūkstošos kadrus, vai vēlaties turpināt video atskaņošanu? Video straumēšanas protokoli parasti izmanto UDP. Tā kā TCP garantē piegādi, tas ir izvēlētais protokols HTTP, FTP, SMTP, POP3 un tā tālāk.
Šajā apmācībā es jūs iepazīstinu ar ligzdu programmēšanu Java. Es iepazīstinu ar virkni klientu-serveru piemēru, kas demonstrē sākotnējā Java I / O ietvara funkcijas, pēc tam pakāpeniski pāriet uz NIO ieviesto funkciju izmantošanu.
Vecās skolas Java kontaktligzdas
Īstenojot pirms NIO, Java TCP klienta ligzdas kodu apstrādā java.net.Socket
klasē. Šis kods atver savienojumu ar serveri:
Socket socket = jauns Socket (serveris, ports);
Reiz mūsu kontaktligzda
gadījums ir savienots ar serveri, mēs varam sākt iegūt ievades un izvades straumes uz atsevišķu. Ievades straumes tiek izmantotas, lai nolasītu datus no servera, savukārt izvades straumes tiek izmantotas datu ierakstīšanai serverī. Mēs varam izpildīt šādas metodes, lai iegūtu ievades un izvades plūsmas:
InputStream iekš = socket.getInputStream (); OutputStream out = socket.getOutputStream ();
Tā kā tās ir parastas straumes, tās pašas straumes, kuras mēs izmantotu, lai lasītu un rakstītu failā, mēs varam tās pārveidot formā, kas vislabāk atbilst mūsu lietošanas gadījumam. Piemēram, mēs varētu ietīt OutputStream
ar PrintStream
lai mēs varētu viegli rakstīt tekstu ar tādām metodēm kā println ()
. Citu piemēru mēs varētu ietīt InputStream
ar BufferedReader
, izmantojot an InputStreamReader
, lai tekstu varētu viegli nolasīt ar tādām metodēm kā readLine ()
.
Java kontaktligzdas klienta piemērs
Apskatīsim īsu piemēru, kas izpilda HTTP GET pret HTTP serveri. HTTP ir sarežģītāks nekā pieļauj mūsu piemērs, taču mēs varam uzrakstīt klienta kodu, lai rīkotos vienkāršākajā gadījumā: pieprasiet resursam no servera, un serveris atgriež atbildi un aizver straumi. Šajā gadījumā ir jāveic šādas darbības:
- Izveidojiet ligzdu tīmekļa serverim, kas klausās 80. portu.
- Iegūt a
PrintStream
uz serveri un nosūtiet pieprasījumuIEGŪT CELU HTTP / 1.0
, kurCELS
ir pieprasītais resurss serverī. Piemēram, ja mēs vēlētos atvērt tīmekļa vietnes sakni, ceļš būtu/
. - Iegūstiet
InputStream
uz serveri, aptiniet to arBufferedReader
un rindu pa rindai lasiet atbildi.
1. saraksts parāda šī piemēra avota kodu.
Saraksts 1. SimpleSocketClientExample.java
pakete com.geekcap.javaworld.simplesocketclient; importēt java.io.BufferedReader; importēt java.io.InputStreamReader; importēt java.io.PrintStream; importēt java.net.Socket; public class SimpleSocketClientExample {public static void main (String [] args) {if (args.length <2) {System.out.println ("Lietojums: SimpleSocketClientExample"); System.exit (0); } Stīgu serveris = args [0]; Virknes ceļš = args [1]; System.out.println ("URL satura ielāde:" + serveris); mēģiniet {// izveidot savienojumu ar serveri Socket socket = new Socket (server, 80); // Izveidojiet ievades un izvades straumes lasīšanai un rakstīšanai uz serveri PrintStream out = new PrintStream (socket.getOutputStream ()); BufferedReader in = new BufferedReader (jauns InputStreamReader (socket.getInputStream ())); // Izpildiet GET HTTP / 1.0 HTTP protokolu, kam seko tukša rinda out.println ("GET" + ceļš + "HTTP / 1.0"); out.println (); // Datu lasīšana no servera, līdz pabeidzim lasīt dokumentu String line = in.readLine (); while (līnija! = null) {System.out.println (līnija); līnija = in.readLine (); } // Aizveriet mūsu straumes in.close (); out.close (); ligzda.slēgt (); } catch (izņēmums e) {e.printStackTrace (); }}}
1. sarakstā tiek pieņemti divi komandrindas argumenti: serveris, ar kuru izveidot savienojumu (pieņemot, ka mēs izveidojam savienojumu ar serveri 80. portā), un resurss, kuru izgūt. Tas rada a Kontaktligzda
kas norāda uz serveri un skaidri norāda portu 80
. Pēc tam tā izpilda komandu:
IEGŪT CELU HTTP / 1.0
Piemēram:
GET / HTTP / 1.0
Kas tikko notika?
Ielādējot tīmekļa lapu no tīmekļa servera, piemēram, www.google.lv
, HTTP klients izmanto DNS serverus, lai atrastu servera adresi: tas sākas ar augstākā līmeņa domēna servera pieprasīšanu com
domēns, kurā domēnam domēna vārdu serveris ir domāts www.google.lv
. Tad tā pieprasa, lai domēna vārdu serveris piešķir IP adresi (vai adreses) www.google.lv
. Pēc tam tas atver ligzdu šim serverim 80. portā. (Vai arī, ja vēlaties definēt citu portu, varat to izdarīt, pievienojot kolu, kam seko porta numurs, piemēram: :8080
.) Visbeidzot, HTTP klients izpilda norādīto HTTP metodi, piemēram, GŪT
, POST
, PUT
, DZĒST
, GALVA
vai OPTI / ONS
. Katrai metodei ir sava sintakse. Kā parādīts iepriekšējos koda fragmentos, GŪT
metode prasa ceļu, kam seko HTTP / versijas numurs
un tukša rinda. Ja mēs vēlētos pievienot HTTP galvenes, mēs to būtu varējuši izdarīt pirms ievadīšanas jaunajā rindā.
1. sarakstā mēs izguvām OutputStream
un ietin to a PrintStream
lai mēs varētu vieglāk izpildīt savas teksta komandas. Mūsu kods ieguva InputStream
, ietin to InputStreamReader
, kas to pārveidoja par a Lasītājs
un pēc tam ietin to a BufferedReader
. Mēs izmantojām PrintStream
izpildīt mūsu GŪT
metodi un pēc tam izmantoja BufferedReader
lasīt atbildi pa rindai, līdz saņēmām a nulle
atbildi, norādot, ka kontaktligzda ir aizvērta.
Tagad izpildiet šo klasi un nododiet šādus argumentus:
java com.geekcap.javaworld.simplesocketclient.SimpleSocketClientExample www.javaworld.com /
Jums vajadzētu redzēt izvadi, kas ir līdzīgs zemāk redzamajam:
Notiek URL satura ielāde: www.javaworld.com HTTP / 1.1 200 OK Datums: svētdiena, 2014. gada 21. septembris 22:20:13 GMT serveris: Apache X-Gas_TTL: 10 Kešatmiņas kontrole: maksimālais vecums = 10 X-GasHost: gas2 .usw X-Cooking-With: Benzīns-Vietējais X-Benzīns-Vecums: 8 Satura garums: 168 Pēdējoreiz modificēts: otrdien, 2012. gada 24. janvārī 00:09:09 GMT Etags: "60001b-a8-4b73af4bf3340" Satura tips : text / html Various: Accept-Encoding Connection: aizvērt benzīna testa lapuPanākumi
Šī izeja parāda testa lapu JavaWorld vietnē. Tā atbildēja, ka runā HTTP versijā 1.1 un atbilde ir 200 OK
.
Java ligzdas servera piemērs
Mēs esam aptvēruši klienta pusi, un, par laimi, servera puses komunikācijas aspekts ir tikpat vienkāršs. No vienkāršota viedokļa process ir šāds:
- Izveidojiet a
ServerSocket
, norādot ostu, kurā klausīties. - Izsaukt
ServerSocket
'spieņemt ()
metode, lai klausītos klienta savienojuma konfigurētajā portā. - Kad klients izveido savienojumu ar serveri,
pieņemt ()
metode atgriež aKontaktligzda
caur kuru serveris var sazināties ar klientu. Tas ir tas patsKontaktligzda
klase, kuru izmantojām klientam, tāpēc process ir tāds pats: iegūstietInputStream
lasīt no klienta unOutputStream
rakstiet klientam. - Ja jūsu serverim jābūt mērogojamam, jūs vēlaties nodot
Kontaktligzda
uz citu pavedienu, lai apstrādātu, lai jūsu serveris varētu turpināt klausīties papildu savienojumus. - Zvaniet
ServerSocket
'spieņemt ()
vēlreiz, lai klausītos citu savienojumu.
Kā jūs drīz redzēsiet, NIO rīcība ar šo scenāriju būtu nedaudz savādāka. Tomēr pagaidām mēs varam tieši izveidot ServerSocket
nododot to ostai, kur klausīties (vairāk par ServerSocketFactory
s nākamajā sadaļā):
ServerSocket serverSocket = jauns ServerSocket (ports);
Un tagad mēs varam pieņemt ienākošos savienojumus, izmantojot pieņemt ()
metode:
Socket socket = serverSocket.accept (); // Rīkojieties ar savienojumu ...
Daudzlīniju programmēšana ar Java ligzdām
Zemāk esošajā 2. sarakstā viss servera kods līdz šim tiek apvienots nedaudz stabilākā piemērā, kurā vairāku pieprasījumu apstrādei tiek izmantoti pavedieni. Parādītais serveris ir atbalss serveris, kas nozīmē, ka tas atsaucas pret jebkuru saņemto ziņojumu.
Kaut arī 2. saraksta piemērs nav sarežģīts, tas paredz dažus no nākamajiem NIO sadaļas jautājumiem. Pievērsiet īpašu uzmanību vītnes koda apjomam, kas mums ir jāraksta, lai izveidotu serveri, kas spēj apstrādāt vairākus vienlaicīgus pieprasījumus.
Saraksts 2. SimpleSocketServer.java
pakete com.geekcap.javaworld.simplesocketclient; importēt java.io.BufferedReader; importēt java.io.I / OException; importēt java.io.InputStreamReader; importēt java.io.PrintWriter; importēt java.net.ServerSocket; importēt java.net.Socket; publiskā klase SimpleSocketServer paplašina Thread {private ServerSocket serverSocket; privātā int osta; privāta būla skriešana = false; public SimpleSocketServer (int ports) {this.port = ports; } public void startServer () {mēģiniet {serverSocket = jauns ServerSocket (ports); this.sākt (); } catch (I / OException e) {e.printStackTrace (); }} public void stopServer () {running = false; tas.traucēt (); } @Orride public void run () {running = true; kamēr (darbojas) {mēģiniet {System.out.println ("Savienojuma klausīšanās"); // Zvans accept (), lai saņemtu nākamo savienojumu Socket socket = serverSocket.accept (); // nododiet ligzdu RequestHandler pavedienam apstrādei RequestHandler requestHandler = jauns RequestHandler (ligzda); requestHandler.start (); } catch (I / OException e) {e.printStackTrace (); }}} public static void main (String [] args) {if (args.length == 0) {System.out.println ("Lietojums: SimpleSocketServer"); System.exit (0); } int ports = Integer.parseInt (args [0]); System.out.println ("Sākt serveri portā:" + ports); SimpleSocketServer serveris = jauns SimpleSocketServer (ports); server.startServer (); // Automātiska izslēgšanās 1 minūtes laikā mēģiniet {Thread.sleep (60000); } catch (izņēmums e) {e.printStackTrace (); } server.stopServer (); }} klases RequestHandler paplašina Thread {private Socket socket; RequestHandler (kontaktligzdas ligzda) {this.socket = ligzda; } @Orride public void run () {mēģiniet {System.out.println ("Saņemts savienojums"); // Iegūt ievades un izvades straumes BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ())); PrintWriter out = jauns PrintWriter (socket.getOutputStream ()); // izrakstiet mūsu galveni klientam out.println ("Echo Server 1.0"); out.skalot (); // Atbalss rindas atpakaļ klientam, līdz klients aizver savienojumu vai mēs saņemam tukšu rindu String line = in.readLine (); while (līnija! = null && līnija.length ()> 0) {out.println ("Atbalss:" + līnija); out.skalot (); līnija = in.readLine (); } // Aizveriet mūsu savienojumu in.close (); out.close (); ligzda.slēgt (); System.out.println ("Savienojums slēgts"); } catch (izņēmums e) {e.printStackTrace (); }}}