Programovanie

Programovanie zásuviek v Jave: Výukový program

Tento výukový program predstavuje úvod do programovania soketov v jazyku Java, počnúc jednoduchým príkladom typu klient-server, ktorý demonštruje základné vlastnosti Java I / O. Predstaví sa vám pôvodný origináljava.io balíček a NIO, neblokujúci I / O (java.nio) API zavedené v prostredí Java 1.4. Na záver uvidíte príklad, ktorý demonštruje vytváranie sietí Java v prostredí NIO.2 implementovanom od Java 7 vpred.

Programovanie zásuviek sa zredukuje na dva systémy, ktoré navzájom komunikujú. Sieťová komunikácia sa všeobecne dodáva v dvoch variantoch: Transport Control Protocol (TCP) a User Datagram Protocol (UDP). TCP a UDP sa používajú na rôzne účely a obe majú jedinečné obmedzenia:

  • TCP je relatívne jednoduchý a spoľahlivý protokol, ktorý umožňuje klientovi nadviazať spojenie so serverom a dvoma systémami na komunikáciu. V TCP každá entita vie, že boli prijaté jej užitočné zaťaženia komunikácie.
  • UDP je a protokol bez pripojenia a je vhodný pre scenáre, keď nevyhnutne nepotrebujete každý paket, aby ste dorazili na miesto určenia, napríklad streamovanie médií.

Ak chcete oceniť rozdiel medzi TCP a UDP, zvážte, čo by sa stalo, keby ste streamovali video z vášho obľúbeného webu a vypadli z neho rámce. Chceli by ste, aby klient spomalil váš film, aby získal chýbajúce snímky, alebo chcete, aby sa video prehrávalo ďalej? Protokoly na streamovanie videa zvyčajne využívajú UDP. Pretože TCP zaručuje doručenie, je to protokol voľby pre HTTP, FTP, SMTP, POP3 atď.

V tomto návode vám predstavím programovanie zásuviek v Jave. Uvádzam sériu príkladov typu klient-server, ktoré demonštrujú funkcie z pôvodného prostredia Java I / O a postupne postupujú k používaniu funkcií predstavených v aplikácii NIO.2.

Staré školské zásuvky Java

V implementáciách pred NIO kód klientskej zásuvky Java TCP spracúva server java.net.Socket trieda. Nasledujúci kód otvára pripojenie k serveru:

 Zásuvka zásuvky = nová zásuvka (server, port); 

Raz náš zásuvka inštancia je pripojená k serveru, môžeme začať získavať vstupné a výstupné toky do servera. Vstupné toky sa používajú na čítanie údajov zo servera, zatiaľ čo výstupné toky sa používajú na zápis údajov na server. Na získanie vstupných a výstupných tokov môžeme vykonať nasledujúce metódy:

 InputStream in = socket.getInputStream (); Výstup OutStream = socket.getOutputStream (); 

Pretože sa jedná o bežné streamy, rovnaké streamy, ktoré by sme použili na čítanie a zápis do súboru, môžeme ich previesť do formy, ktorá najlepšie slúži nášmu prípadu použitia. Napríklad by sme mohli zabaliť OutputStream s PrintStream aby sme mohli ľahko písať text metódami ako println (). Ako ďalší príklad by sme mohli zabaliť InputStream s BufferedReaderprostredníctvom InputStreamReader, aby bolo možné ľahko čítať text metódami ako readLine ().

download Stiahnite si zdrojový kód Zdrojový kód pre „Programovanie zásuviek v Jave: Výukový program“. Vytvoril Steven Haines pre JavaWorld.

Príklad klienta soketu Java

Prejdime si krátky príklad, ktorý vykoná HTTP GET proti serveru HTTP. Protokol HTTP je sofistikovanejší, ako povoľuje náš príklad, ale môžeme napísať kód klienta, aby sme zvládli najjednoduchší prípad: vyžiadať si zo servera zdroj a server vráti odpoveď a zavrie stream. Tento prípad vyžaduje nasledujúce kroky:

  1. Vytvorte zásuvku pre webový server počúvajúci na porte 80.
  2. Získajte a PrintStream odoslať na server ZÍSKAJTE CESTU HTTP / 1.0, kde CESTA je požadovaný prostriedok na serveri. Napríklad, ak by sme chceli otvoriť koreň webovej stránky, potom by bola cesta /.
  3. Získať InputStream na server, zabaľte ho do BufferedReader a prečítajte si odpoveď po riadkoch.

Výpis 1 zobrazuje zdrojový kód tohto príkladu.

Zoznam 1. SimpleSocketClientExample.java

balíček com.geekcap.javaworld.simplesocketclient; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; verejná trieda SimpleSocketClientExample {verejné statické void main (String [] args) {if (args.length <2) {System.out.println ("Použitie: SimpleSocketClientExample"); System.exit (0); } Reťazcový server = args [0]; Cesta reťazca = args [1]; System.out.println ("Načítava sa obsah adresy URL:" + server); skúste {// Pripojiť k serveru Socket socket = new Socket (server, 80); // Vytváranie vstupných a výstupných prúdov na čítanie a zápis na server PrintStream out = nový PrintStream (socket.getOutputStream ()); BufferedReader in = nový BufferedReader (nový InputStreamReader (socket.getInputStream ())); // Postupujte podľa protokolu HTTP GET HTTP / 1.0, za ktorým nasleduje prázdny riadok out.println ("GET" + cesta + "HTTP / 1.0"); out.println (); // Čítame údaje zo servera, kým nedočítame dokument String line = in.readLine (); while (riadok! = null) {System.out.println (riadok); line = in.readLine (); } // Zatvorte naše streamy in.close (); out.close (); socket.close (); } catch (Výnimka e) {e.printStackTrace (); }}} 

Zoznam 1 prijíma dva argumenty príkazového riadku: server, ku ktorému sa chcete pripojiť (za predpokladu, že sa pripájame k serveru na porte 80), a prostriedok, ktorý sa má načítať. Vytvára a Zásuvka ktorý smeruje na server a výslovne určuje port 80. Potom vykoná príkaz:

ZÍSKAJTE CESTU HTTP / 1.0 

Napríklad:

GET / HTTP / 1.0 

Čo sa práve stalo?

Pri načítaní webovej stránky z webového servera, ako je napr www.google.com, HTTP klient používa servery DNS na zistenie adresy servera: začína sa tým, že sa od servera domény najvyššej úrovne požaduje server com doména, kde je smerodajný server názvov domén pre doménu www.google.com. Potom požiada server doménových mien o adresu IP (alebo adresy) www.google.com. Ďalej otvorí soket na tomto serveri na porte 80. (Alebo ak chcete definovať iný port, môžete to urobiť pridaním dvojbodky a čísla portu, napríklad: :8080.) Nakoniec klient HTTP vykoná zadanú metódu HTTP, napríklad ZÍSKAJTE, POST, PUT, ODSTRÁNIŤ, HLAVAalebo MOŽNOSTI. Každá metóda má svoju vlastnú syntax. Ako je uvedené vo vyššie uvedenom výpise kódu, znak ZÍSKAJTE metóda vyžaduje cestu, za ktorou nasleduje HTTP / číslo verzie a prázdny riadok. Ak by sme chceli pridať hlavičky HTTP, mohli sme to urobiť pred zadaním nového riadku.

V zozname 1 sme získali OutputStream a zabalil do a PrintStream aby sme mohli ľahšie vykonávať naše textové príkazy. Náš kód získal InputStream, zabalené v InputStreamReader, ktorá ho previedla na a Čitateľ, a potom to zabalil do a BufferedReader. Použili sme PrintStream vykonať našu ZÍSKAJTE metóda a potom sa použila metóda BufferedReader čítať odpoveď riadok po riadku, kým nedostaneme a nulový odpoveď, ktorá naznačuje, že soket bol zatvorený.

Teraz vykonajte túto triedu a odovzdajte jej nasledujúce argumenty:

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

Mali by ste vidieť výstup podobný nasledujúcemu:

Načítava sa obsah adresy URL: www.javaworld.com HTTP / 1,1 200 OK Dátum: ne, 21. septembra 2014 22:20:13 GMT server: Apache X-Gas_TTL: 10 Cache-Control: max-age = 10 X-GasHost: gas2 .usw X-Cooking-With: benzín-lokálny X-benzín-vek: 8 obsahová dĺžka: 168 posledná zmena: ut, 24. januára 2012 00:09:09 GMT Etag: „60001b-a8-4b73af4bf3340“ obsahový typ : text / html Variabilné: Pripojenie na prijímanie a kódovanie: zatvorte stránku na testovanie benzínu

Úspech

Tento výstup zobrazuje testovaciu stránku na webe JavaWorld. Odpovedal späť, že hovorí HTTP verzia 1.1, a odpoveď je 200 OK.

Príklad servera Java socket

Pokryli sme stranu klienta a našťastie je komunikačný aspekt na strane servera rovnako ľahký. Zo zjednodušeného hľadiska je proces nasledovný:

  1. Vytvor ServerSocket, s uvedením portu, na ktorom sa má počúvať.
  2. Vyvolajte ServerSocketje súhlasiť() metóda počúvania na nakonfigurovanom porte pre pripojenie klienta.
  3. Keď sa klient pripojí k serveru, server súhlasiť() metóda vracia a Zásuvka prostredníctvom ktorého môže server komunikovať s klientom. To je to isté Zásuvka triedy, ktorú sme použili pre nášho klienta, takže postup je rovnaký: získajte InputStream čítať od klienta a OutputStream napíš klientovi.
  4. Ak je potrebné, aby bol váš server škálovateľný, mali by ste vyhovieť Zásuvka do iného vlákna na spracovanie, aby váš server mohol pokračovať v počúvaní ďalších pripojení.
  5. Zavolajte ServerSocketje súhlasiť() znova počúvať ďalšie pripojenie.

Ako čoskoro uvidíte, zaobchádzanie NIO s týmto scenárom by bolo trochu iné. Zatiaľ však môžeme priamo vytvoriť a ServerSocket odovzdaním portu, ktorý chcete počúvať (viac o ServerSocketFactorys v ďalšej časti):

 ServerSocket serverSocket = nový ServerSocket (port); 

A teraz môžeme prijímať prichádzajúce spojenia cez súhlasiť() metóda:

 Socket socket = serverSocket.accept (); // Riešenie spojenia ... 

Viacvláknové programovanie so zásuvkami Java

Výpis 2 nižšie dáva všetok doterajší kód servera dohromady do trochu robustnejšieho príkladu, ktorý používa vlákna na vybavenie viacerých požiadaviek. Zobrazený server je echo server, čo znamená, že odráža všetky správy, ktoré prijme.

Aj keď príklad v zozname 2 nie je zložitý, predpokladá niečo z toho, čo sa chystá v nasledujúcej časti o NIO. Venujte zvláštnu pozornosť množstvu vláknového kódu, ktorý musíme napísať, aby sme mohli vytvoriť server, ktorý zvládne viac súčasných požiadaviek.

Zoznam 2. SimpleSocketServer.java

balíček com.geekcap.javaworld.simplesocketclient; import java.io.BufferedReader; import java.io.I / OException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; verejná trieda SimpleSocketServer rozširuje vlákno {private ServerSocket serverSocket; súkromný int port; private boolean running = false; public SimpleSocketServer (int port) {this.port = port; } public void startServer () {try {serverSocket = nový ServerSocket (port); this.start (); } catch (I / OException e) {e.printStackTrace (); }} public void stopServer () {running = false; this.interrupt (); } @Override public void run () {running = true; while (running) {try {System.out.println ("Listening for a connection"); // Zavolajte accept () na prijatie ďalšieho spojenia Socket socket = serverSocket.accept (); // Preneste soket na vlákno RequestHandler na spracovanie RequestHandler requestHandler = nový RequestHandler (socket); requestHandler.start (); } catch (I / OException e) {e.printStackTrace (); }}} public static void main (String [] args) {if (args.length == 0) {System.out.println ("Použitie: SimpleSocketServer"); System.exit (0); } int port = Integer.parseInt (args [0]); System.out.println ("Spustiť server na porte:" + port); Server SimpleSocketServer = nový SimpleSocketServer (port); server.startServer (); // Automatické vypnutie za 1 minútu skúste {Thread.sleep (60000); } catch (Výnimka e) {e.printStackTrace (); } server.stopServer (); }} class RequestHandler extends Thread {private Socket socket; RequestHandler (Socket socket) {this.socket = socket; } @Override public void run () {try {System.out.println ("Prijalo pripojenie"); // Získanie vstupných a výstupných prúdov BufferedReader in = new BufferedReader (nový InputStreamReader (socket.getInputStream ())); PrintWriter out = nový PrintWriter (socket.getOutputStream ()); // Vypíšeme našu hlavičku klientovi out.println ("Echo Server 1.0"); out.flush (); // Odozva riadkov späť na klienta, kým klient neukončí pripojenie alebo kým nedostaneme prázdny riadok String line = in.readLine (); while (line! = null && line.length ()> 0) {out.println ("Echo:" + riadok); out.flush (); line = in.readLine (); } // Uzavrieme naše spojenie in.close (); out.close (); socket.close (); System.out.println ("Pripojenie ukončené"); } catch (Výnimka e) {e.printStackTrace (); }}} 
$config[zx-auto] not found$config[zx-overlay] not found