Programiranje

Programiranje vtičnic v Javi: Vadnica

Ta vadnica je uvod v programiranje vtičnic v Javi, začenši s preprostim primerom odjemalec-strežnik, ki prikazuje osnovne značilnosti Java I / O. Predstavili se vam bosta oba izvirnikajava.io paket in NIO, neblokirajoči V / I (java.nio) API-ji, predstavljeni v Javi 1.4. Končno boste videli primer, ki prikazuje omrežje Java, kot je bilo izvedeno od Jave 7 naprej, v NIO.2.

Programiranje vtičnic se nanaša na dva sistema, ki komunicirata med seboj. Omrežna komunikacija ima na splošno dva okusa: protokol za nadzor prometa (TCP) in protokol za uporabniške datagrame (UDP). TCP in UDP se uporabljata za različne namene in imata edinstvene omejitve:

  • TCP je razmeroma preprost in zanesljiv protokol, ki odjemalcu omogoča povezavo s strežnikom in obema sistemoma za komunikacijo. V TCP vsak subjekt ve, da je bil prejet njegov komunikacijski tovor.
  • UDP je protokol brez povezave in je primeren za scenarije, v katerih ni nujno, da vsak paket prispe na cilj, na primer pretakanje medijev.

Če želite ceniti razliko med TCP in UDP, razmislite, kaj bi se zgodilo, če bi pretakali video s svojega najljubšega spletnega mesta in bi padli okvirji. Bi raje, da odjemalec upočasni vaš film, da sprejme manjkajoče sličice, ali bi raje nadaljeval predvajanje videoposnetka? Protokoli za pretakanje videa običajno uporabljajo UDP. Ker TCP zagotavlja dostavo, je to izbrani protokol za HTTP, FTP, SMTP, POP3 itd.

V tej vadnici vam predstavljam programiranje vtičnic v Javi. Predstavljam vrsto primerov odjemalec-strežnik, ki prikazujejo funkcije iz prvotnega okolja Java I / O, nato pa postopoma napredujejo do uporabe funkcij, predstavljenih v NIO.2.

Starošolske vtičnice Java

Pri izvedbah pred NIO kodo odjemalske vtičnice Java TCP obravnava java.net.Vtičnica razred. Naslednja koda odpre povezavo s strežnikom:

 Vtičnica vtičnice = nova vtičnica (strežnik, vrata); 

Enkrat naš vtičnica primer je povezan s strežnikom, lahko začnemo pridobivati ​​vhodne in izhodne tokove do sever. Vhodni tokovi se uporabljajo za branje podatkov s strežnika, medtem ko se izhodni tokovi uporabljajo za zapisovanje podatkov v strežnik. Za pridobitev vhodnih in izhodnih tokov lahko izvedemo naslednje metode:

 InputStream v = socket.getInputStream (); OutputStream out = socket.getOutputStream (); 

Ker gre za običajne tokove, iste tokove, ki bi jih uporabljali za branje in zapisovanje v datoteko, jih lahko pretvorimo v obliko, ki najbolje ustreza našemu primeru uporabe. Na primer, lahko zavijemo Izhodni tok z PrintStream tako da lahko enostavno napišemo besedilo s podobnimi metodami println (). Za drug primer bi lahko zavili InputStream z BufferedReader, prek InputStreamReader, z namenom lažjega branja besedila z metodami, kot so readLine ().

prenos Prenesite izvorno kodo Izvorna koda za "Programiranje vtičnic v Javi: Vadnica." Ustvaril Steven Haines za JavaWorld.

Primer odjemalca Java vtičnice

Poglejmo si kratek primer, ki izvede HTTP GET proti strežniku HTTP. HTTP je bolj dovršen, kot to dopušča naš primer, vendar lahko za najenostavnejši primer napišemo odjemalsko kodo: zahtevamo vir od strežnika in strežnik vrne odgovor in zapre tok. Ta primer zahteva naslednje korake:

  1. Ustvarite vtičnico spletnega strežnika, ki posluša na vratih 80.
  2. Pridobite a PrintStream na strežnik in pošljite zahtevo PRIDI POT HTTP / 1.0, kje POT je zahtevani vir na strežniku. Če bi na primer želeli odpreti koren spletnega mesta, bi bila pot /.
  3. Pridobite InputStream na strežnik, ga zavijte z BufferedReader in preberite odgovor po vrsticah.

Seznam 1 prikazuje izvorno kodo za ta primer.

Seznam 1. SimpleSocketClientExample.java

paket com.geekcap.javaworld.simplesocketclient; import java.io.BufferedReader; uvoz java.io.InputStreamReader; uvoz java.io.PrintStream; uvoz java.net.Socket; javni razred SimpleSocketClientExample {public static void main (String [] args) {if (args.length <2) {System.out.println ("Usage: SimpleSocketClientExample"); System.exit (0); } String strežnik = args [0]; Pot niza = args [1]; System.out.println ("Nalaganje vsebine URL-ja:" + strežnik); poskusite {// Povežite se s strežnikom Socket socket = new Socket (server, 80); // Ustvarjanje vhodnih in izhodnih tokov za branje s strežnika in pisanje na strežnik PrintStream out = nov PrintStream (socket.getOutputStream ()); BufferedReader v = new BufferedReader (nov InputStreamReader (socket.getInputStream ())); // Sledite protokolu HTTP GET HTTP / 1.0, čemur sledi prazna vrstica out.println ("GET" + pot + "HTTP / 1.0"); out.println (); // Branje podatkov s strežnika, dokler ne zaključimo branja dokumenta String line = in.readLine (); while (vrstica! = null) {System.out.println (vrstica); vrstica = in.readLine (); } // // zaprite naše tokove v.close (); out.close (); socket.close (); } catch (izjema e) {e.printStackTrace (); }}} 

Seznam 1 sprejema dva argumenta ukazne vrstice: strežnik, na katerega se želimo povezati (ob predpostavki, da se povezujemo s strežnikom na vratih 80), in vir, ki ga je treba pridobiti. Ustvari a Vtičnica ki kaže na strežnik in izrecno določa vrata 80. Nato izvrši ukaz:

PRIDI POT HTTP / 1.0 

Na primer:

GET / HTTP / 1.0 

Kaj se je pravkar zgodilo?

Ko s spletnega strežnika pridobite spletno stran, na primer www.google.com, odjemalec HTTP uporablja strežnike DNS za iskanje naslova strežnika: najprej začne s strežnikom domene najvišje ravni za com domena, kjer je avtoritativni strežnik imena domene za www.google.com. Nato od strežnika imena domene zahteva naslov IP (ali naslove) za www.google.com. Nato odpre vtičnico za ta strežnik na vratih 80. (Če pa želite določiti druga vrata, lahko to storite tako, da dodate dvopičje, ki mu sledi številka vrat, na primer: :8080.) Na koncu odjemalec HTTP izvede določeno metodo HTTP, kot je GET, OBJAVI, PUT, IZBRIŠI, GLAVA, ali OPCIJE. Vsaka metoda ima svojo sintakso. Kot je prikazano v zgornjih odrezkih kode, GET metoda zahteva pot, ki ji sledi HTTP / številka različice in prazna vrstica. Če bi želeli dodati glave HTTP, bi to lahko storili že pred vstopom v novo vrstico.

V seznamu 1 smo našli datoteko Izhodni tok in ga zavil v PrintStream tako da bomo lažje izvajali besedilne ukaze. Naša koda je dobila InputStream, zavit v InputStreamReader, ki ga je pretvoril v a Bralecin nato to zavil v BufferedReader. Uporabili smo PrintStream izvršiti našo GET in nato uporabil BufferedReader prebrati odziv po vrsticah, dokler nismo prejeli nič odgovor, ki kaže, da je bila vtičnica zaprta.

Zdaj zaženite ta razred in mu posredujte naslednje argumente:

java com.geekcap.javaworld.simplesocketclient.SimpleSocketClientExample www.javaworld.com / 

Morali bi videti izhod, podoben spodnjemu:

Nalaganje vsebine URL-ja: www.javaworld.com HTTP / 1.1 200 OK Datum: Nedelja, 21. september 2014 22:20:13 GMT Strežnik: Apache X-Gas_TTL: 10 Nadzor predpomnilnika: max-age = 10 X-GasHost: gas2 .usw X-Cooking-With: Bencin-Lokalni X-bencin-Starost: 8 Dolžina vsebine: 168 Zadnja sprememba: Torek, 24. januar 2012 00:09:09 GMT Etag: "Tip vsebine" 60001b-a8-4b73af4bf3340 " : text / html Vary: Povezava za sprejemanje in kodiranje: zaprite preizkusno stran o bencinu

Uspeh

Ta rezultat prikazuje preizkusno stran na spletnem mestu JavaWorld. Odgovoril je, da govori HTTP različico 1.1 in odgovor je 200 OK.

Primer strežnika Java vtičnice

Pokrili smo odjemalsko stran in na srečo je komunikacijski vidik strežniške strani prav tako enostaven. Z poenostavljenega vidika je postopek naslednji:

  1. Ustvariti ServerSocket, ki določa vrata za poslušanje.
  2. Prikliči ServerSocketje sprejme () metoda za poslušanje na konfiguriranih vratih za odjemalsko povezavo.
  3. Ko se odjemalec poveže s strežnikom, se sprejme () metoda vrne a Vtičnica prek katerega lahko strežnik komunicira s stranko. To je isto Vtičnica razred, ki smo ga uporabili za našo stranko, zato je postopek enak: pridobite InputStream branje od stranke in Izhodni tok piši stranki.
  4. Če mora biti strežnik razširljiv, boste želeli prenesti datoteko Vtičnica v drugo nit za obdelavo, da bo lahko strežnik še naprej poslušal dodatne povezave.
  5. Pokliči ServerSocketje sprejme () znova poslušajte drugo povezavo.

Kot boste kmalu videli, bi bilo ravnanje NIO s tem scenarijem nekoliko drugačno. Za zdaj pa lahko neposredno ustvarimo ServerSocket tako da mu posredujete vrata, ki jih želite poslušati (več o ServerSocketFactorys v naslednjem razdelku):

 ServerSocket serverSocket = novo ServerSocket (vrata); 

In zdaj lahko sprejemamo dohodne povezave prek sprejme () metoda:

 Socket socket = serverSocket.accept (); // Upravljanje povezave ... 

Večnitno programiranje z vtičnicami Java

V spodnjem seznamu 2 je vsa strežniška koda do zdaj združena v nekoliko močnejši primer, ki uporablja niti za obdelavo več zahtev. Prikazani strežnik je odmevni strežnik, kar pomeni, da odzvanja vsako sporočilo, ki ga prejme.

Čeprav primer v seznamu 2 ni zapleten, predvideva nekaj, kar se bo pojavilo v naslednjem poglavju o NIO. Posebej bodite pozorni na količino kode za navoje, ki jo moramo napisati, da zgradimo strežnik, ki lahko obravnava več hkratnih zahtev.

Seznam 2. SimpleSocketServer.java

paket com.geekcap.javaworld.simplesocketclient; import java.io.BufferedReader; uvoz java.io.I / OException; uvoz java.io.InputStreamReader; uvoz java.io.PrintWriter; uvoz java.net.ServerSocket; uvoz java.net.Socket; javni razred SimpleSocketServer razširja Thread {private ServerSocket serverSocket; zasebno int pristanišče; zasebno logično delovanje = false; javni SimpleSocketServer (int port) {this.port = port; } javna void startServer () {poskusite {serverSocket = novo ServerSocket (vrata); this.start (); } catch (I / OException e) {e.printStackTrace (); }} javna void stopServer () {teče = napačno; this.interrupt (); } @Override public void run () {running = true; med (tekom) {poskusite {System.out.println ("Poslušanje povezave"); // pokličite accept () za prejem naslednje povezave Socket socket = serverSocket.accept (); // posredovanje vtičnice niti RequestHandler za obdelavo RequestHandler requestHandler = new RequestHandler (vtičnica); requestHandler.start (); } catch (I / OException e) {e.printStackTrace (); }}} javna statična void main (String [] args) {if (args.length == 0) {System.out.println ("Usage: SimpleSocketServer"); System.exit (0); } int port = Integer.parseInt (args [0]); System.out.println ("Zaženi strežnik na vratih:" + vrata); Strežnik SimpleSocketServer = nov SimpleSocketServer (vrata); server.startServer (); // Samodejno zaustavitev v 1 minuti poskusite {Thread.sleep (60000); } catch (izjema e) {e.printStackTrace (); } server.stopServer (); }} razred RequestHandler razširja Thread {private Socket socket; RequestHandler (vtičnica vtičnice) {this.socket = vtičnica; } @Override public void run () {try {System.out.println ("Prejeta povezava"); // Pridobite vhodne in izhodne tokove BufferedReader v = new BufferedReader (new InputStreamReader (socket.getInputStream ())); PrintWriter out = novo PrintWriter (socket.getOutputStream ()); // Zapiši našo glavo odjemalcu out.println ("Echo Server 1.0"); out.flush (); // Vrne se odjemalca nazaj na odjemalca, dokler odjemalec ne zapre povezave ali ne dobimo prazne vrstice String line = in.readLine (); while (line! = null && line.length ()> 0) {out.println ("Echo:" + line); out.flush (); vrstica = in.readLine (); } // Zapremo našo povezavo v.close (); out.close (); socket.close (); System.out.println ("Povezava zaprta"); } catch (izjema e) {e.printStackTrace (); }}} 
$config[zx-auto] not found$config[zx-overlay] not found