java.io
paketti ja NIO, estämätön I / O (java.nio
) Java 1.4: ssä esitetyt sovellusliittymät. Lopuksi näet esimerkin, joka osoittaa Java-verkostoitumisen Java 7: stä eteenpäin toteutettuna NIO.2: ssa.Socket-ohjelmointi tarkoittaa kahta järjestelmää, jotka ovat yhteydessä toisiinsa. Yleensä verkkoviestinnässä on kaksi makua: Transport Control Protocol (TCP) ja User Datagram Protocol (UDP). TCP: tä ja UDP: tä käytetään eri tarkoituksiin, ja molemmilla on ainutlaatuiset rajoitukset:
- TCP on suhteellisen yksinkertainen ja luotettava protokolla, jonka avulla asiakas voi muodostaa yhteyden palvelimeen ja molemmat järjestelmät kommunikoida. TCP: ssä kukin yksikkö tietää, että sen viestinnän hyötykuormat on vastaanotettu.
- UDP on a Yhteydetön protokolla ja on hyvä tilanteisiin, joissa et välttämättä tarvitse kaikkia paketteja saapuaksesi määränpäähänsä, kuten median suoratoisto.
Arvioidaksesi eron TCP: n ja UDP: n välillä, mieti, mitä tapahtuisi, jos suoratoistat videota suosikkisivustoltasi ja se pudottaisi kehyksiä. Haluatko mieluummin, että asiakas hidastaa elokuvasi vastaanottamaan puuttuvat kehykset, vai haluaisitko, että videon toisto jatkuu? Videon suoratoistoprotokollat käyttävät yleensä UDP: tä. Koska TCP takaa toimituksen, se on valittu protokolla HTTP: lle, FTP: lle, SMTP: lle, POP3: lle ja niin edelleen.
Tässä opetusohjelmassa esitän sinut Java-ohjelmointiin. Esitän sarjan asiakas-palvelin-esimerkkejä, jotka esittävät ominaisuuksia alkuperäisestä Java I / O -kehyksestä ja etenevät sitten vähitellen NIO: n sisältämien ominaisuuksien käyttöön.2.
Vanhan koulun Java-pistorasiat
NIO: ta edeltävissä toteutuksissa Java TCP -asiakasohjelmakoodikoodia käsittelee java.net. pistorasia
luokassa. Seuraava koodi avaa yhteyden palvelimeen:
Socket socket = uusi Socket (palvelin, portti);
Kerran meidän pistorasiaan
Esimerkki on kytketty palvelimelle, voimme alkaa hankkia tulo- ja lähtövirtoja erillislaitteeseen. Tulovirtauksia käytetään tietojen lukemiseen palvelimelta, kun taas lähtövirtauksia käytetään tietojen kirjoittamiseen palvelimelle. Voimme suorittaa seuraavat menetelmät tulo- ja lähtövirtojen saamiseksi:
InputStream sisään = socket.getInputStream (); OutputStream out = socket.getOutputStream ();
Koska nämä ovat tavallisia virtoja, samoja virtoja, joita käytettäisimme lukemaan tiedostosta ja kirjoittamaan tiedostoon, voimme muuntaa ne muotoon, joka parhaiten palvelee käyttötapaustamme. Voisimme esimerkiksi kääriä OutputStream
kanssa PrintStream
jotta voimme kirjoittaa tekstiä helposti esimerkiksi println ()
. Toisen esimerkin voisimme kääriä InputStream
kanssa Puskuroitu lukija
, kautta InputStreamReader
, jotta tekstiä voidaan helposti lukea esimerkiksi Lue rivi()
.
Esimerkki Java socket -asiakasohjelmasta
Selvitetään lyhyt esimerkki, joka suorittaa HTTP GET: n HTTP-palvelinta vastaan. HTTP on kehittyneempi kuin esimerkkimme sallii, mutta voimme kirjoittaa asiakaskoodin yksinkertaisen tapauksen käsittelemiseksi: pyydä resurssi palvelimelta ja palvelin palauttaa vastauksen ja sulkee virran. Tämä tapaus vaatii seuraavat vaiheet:
- Luo liitäntä verkkopalvelimelle, joka kuuntelee porttia 80.
- Hanki a
PrintStream
palvelimelle ja lähetä pyyntöHANKI PATH HTTP / 1.0
, missäPATH
on palvelimen pyydetty resurssi. Esimerkiksi, jos haluaisimme avata verkkosivuston juuren, polku olisi/
. - Hanki
InputStream
palvelimelle, kääri se aPuskuroitu lukija
ja lukea vastaus rivi riviltä.
Listaus 1 näyttää tämän esimerkin lähdekoodin.
Listaus 1. SimpleSocketClientExample.java
paketti com.geekcap.javaworld.simplesocketclient; tuo java.io.BufferedReader; tuo java.io.InputStreamReader; tuo java.io.PrintStream; tuo java.net.Socket; public class SimpleSocketClientExample {public static void main (String [] args) {if (args.pituus <2) {System.out.println ("Käyttö: SimpleSocketClientExample"); System.exit (0); } Merkkijonopalvelin = args [0]; Merkkijonopolku = args [1]; System.out.println ("Ladataan URL-osoitteen sisältöä:" + palvelin); kokeile {// Yhdistä palvelimeen Socket socket = new Socket (server, 80); // Luo sisään- ja ulostulovirrat, joita voi lukea ja kirjoittaa palvelimelta. PrintStream out = new PrintStream (socket.getOutputStream ()); BufferedReader in = new BufferedReader (uusi InputStreamReader (socket.getInputStream ())); // Seuraa GET HTTP / 1.0: n HTTP-protokollaa, jota seuraa tyhjä rivi out.println ("GET" + polku + "HTTP / 1.0"); out.println (); // Lue tiedot palvelimelta, kunnes olemme lukeneet asiakirjan String line = in.readLine (); while (rivi! = null) {System.out.println (rivi); rivi = in.readLine (); } // Sulje virtamme in.close (); out.close (); pistorasia.sulje (); } catch (Poikkeus e) {e.printStackTrace (); }}}
Listaus 1 hyväksyy kaksi komentoriviargumenttia: palvelin, johon yhteys muodostetaan (olettaen, että muodostamme yhteyden palvelimeen portissa 80) ja noutettava resurssi. Se luo Pistoke
joka osoittaa palvelimeen ja määrittää nimenomaisesti portin 80
. Sitten se suorittaa komennon:
HANKI PATH HTTP / 1.0
Esimerkiksi:
GET / HTTP / 1.0
Mitä juuri tapahtui?
Kun haet verkkosivun verkkopalvelimelta, kuten www.google.fi
, HTTP-asiakas etsii palvelimen osoitteen DNS-palvelimien avulla: se aloitetaan pyytämällä ylätason verkkotunnuspalvelimelta com
verkkotunnus, jossa arvovaltainen verkkotunnuspalvelin on www.google.fi
. Sitten se pyytää kyseiseltä verkkotunnuspalvelimelta IP-osoitetta (tai osoitteita) www.google.fi
. Seuraavaksi se avaa kannan tälle palvelimelle portissa 80. (Tai, jos haluat määrittää toisen portin, voit tehdä sen lisäämällä kaksoispisteen, jota seuraa portin numero, esimerkiksi: :8080
.) Lopuksi HTTP-asiakas suorittaa määritetyn HTTP-menetelmän, kuten SAADA
, LÄHETTÄÄ
, LAITTAA
, POISTAA
, PÄÄ
tai OPTI / ONS
. Jokaisella menetelmällä on oma syntaksinsa. Kuten yllä olevista koodinpätkistä näkyy, SAADA
menetelmä edellyttää polkua, jota seuraa HTTP / versionumero
ja tyhjä rivi. Jos halusimme lisätä HTTP-otsikot, olisimme voineet tehdä niin ennen uuden rivin syöttämistä.
Luettelossa 1 haimme OutputStream
ja kääritty se a PrintStream
jotta voimme helpommin suorittaa tekstipohjaiset komentomme. Koodimme sai InputStream
, kääritty se InputStreamReader
, joka muunsi sen a: ksi Lukija
ja kääri sen sitten a Puskuroitu lukija
. Käytimme PrintStream
toteuttaa meidän SAADA
menetelmää ja käytti sitten Puskuroitu lukija
lukea vastauksia rivi kerrallaan, kunnes saimme a tyhjä
vastaus, mikä osoittaa, että pistoke oli suljettu.
Suorita nyt tämä luokka ja anna sille seuraavat argumentit:
java com.geekcap.javaworld.simplesocketclient.SimpleSocketClientExample www.javaworld.com /
Sinun pitäisi nähdä samanlainen lähtö kuin alla:
Ladataan URL-osoitteen sisältöä: www.javaworld.com HTTP / 1.1 200 OK Päivämäärä: su, 21. syyskuuta 2014 22:20:13 GMT-palvelin: Apache X-Gas_TTL: 10 Välimuistin hallinta: max-ikä = 10 X-GasHost: gas2 .usw X-Cooking-With: Bensiini-Paikallinen X-Bensiini-Ikä: 8 Sisällön pituus: 168 Muokattu viimeksi: Tiistaina, 24. tammikuuta 2012 00:09:09 GMT Etag: "60001b-a8-4b73af4bf3340" Sisältötyyppi : teksti / html Vaihtelee: Hyväksy-koodaava yhteys: sulje bensiinitestisivuMenestys
Tämä tulos näyttää testisivun JavaWorldin verkkosivustolla. Se vastasi, että puhuu HTTP-versiota 1.1 ja vastaus on 200 OK
.
Esimerkki Java-socket-palvelimesta
Olemme käsittäneet asiakaspuolen ja onneksi palvelinpuolen viestintä on yhtä helppoa. Yksinkertaistetusta näkökulmasta prosessi on seuraava:
- Luo
ServerSocket
, määritetään portti kuunneltavaksi. - Kutsu
ServerSocket
onhyväksyä()
tapa kuunnella määritettyä porttia asiakasyhteydelle. - Kun asiakas muodostaa yhteyden palvelimeen,
hyväksyä()
method palauttaa aPistoke
jonka kautta palvelin voi kommunikoida asiakkaan kanssa. Tämä on samaPistoke
luokka, jota käytimme asiakkaallemme, joten prosessi on sama: hankiInputStream
lukea asiakkaalta jaOutputStream
kirjoita asiakkaalle. - Jos palvelimesi on oltava skaalautuva, sinun on siirrettävä
Pistoke
toiseen ketjuun käsiteltäväksi, jotta palvelimesi voi jatkaa lisäyhteyksien kuuntelua. - Soita
ServerSocket
onhyväksyä()
menetelmää uudelleen kuunnellaksesi toista yhteyttä.
Kuten pian näette, NIO: n käsittely tässä tilanteessa olisi hieman erilainen. Toistaiseksi voimme kuitenkin luoda suoraan ServerSocket
välittämällä sille portti kuunneltavaksi (lisätietoja ServerSocketFactory
s seuraavassa osassa):
ServerSocket serverSocket = uusi ServerSocket (portti);
Ja nyt voimme hyväksyä saapuvat yhteydet hyväksyä()
menetelmä:
Socket socket = serverSocket.accept (); // Käsittele yhteyttä ...
Monisäikeinen ohjelmointi Java-liittimillä
Alla olevassa luettelossa 2 kaikki palvelinkoodi toistaiseksi yhdistetään hieman vankemmaksi esimerkiksi, joka käyttää ketjuja useiden pyyntöjen käsittelemiseen. Näytetty palvelin on kaikupalvelin, mikä tarkoittaa, että se toistaa kaikki saamansa viestit.
Vaikka Listing 2: n esimerkki ei ole monimutkainen, se ennakoi joitain NIO: n seuraavassa osassa esiintyviä asioita. Kiinnitä erityistä huomiota ketjutuskoodin määrään, joka meidän on kirjoitettava, jotta voimme rakentaa palvelimen, joka pystyy käsittelemään useita samanaikaisia pyyntöjä.
Listaus 2. SimpleSocketServer.java
paketti com.geekcap.javaworld.simplesocketclient; tuo java.io.BufferedReader; tuoda java.io.I / OException; tuo java.io.InputStreamReader; tuo java.io.PrintWriter; tuo java.net.ServerSocket; tuo java.net.Socket; public class SimpleSocketServer laajentaa säiettä {private ServerSocket serverSocket; yksityinen int-portti; yksityinen totuusarvo = epätosi; public SimpleSocketServer (int-portti) {this.port = portti; } public void startServer () {kokeile {serverSocket = uusi ServerSocket (portti); tämä.aloitus (); } catch (I / OException e) {e.printStackTrace (); }} public void stopServer () {running = false; tämä. keskeytä (); } @Override public void run () {running = true; kun (käynnissä) {kokeile {System.out.println ("Yhteyden kuuntelu"); // Soita accept () seuraavan yhteyden vastaanottamiseksi Socket socket = serverSocket.accept (); // Siirrä liitäntä RequestHandler-säikeelle käsittelyä varten RequestHandler requestHandler = uusi RequestHandler (socket); requestHandler.start (); } catch (I / OException e) {e.printStackTrace (); }}} public static void main (Merkkijono [] args) {if (args.length == 0) {System.out.println ("Käyttö: SimpleSocketServer"); System.exit (0); } int port = Kokonaisluku.parseInt (argumentit [0]); System.out.println ("Käynnistä palvelin portissa:" + portti); SimpleSocketServer-palvelin = uusi SimpleSocketServer (portti); server.startServer (); // Sammutetaan automaattisesti minuutin kuluttua, kokeile {Thread.sleep (60000); } catch (Poikkeus e) {e.printStackTrace (); } server.stopServer (); }} luokka RequestHandler laajentaa Thread {private Socket socket; RequestHandler (Socket socket) {this.pistoke = pistorasia; } @Override public void run () {kokeile {System.out.println ("Vastaanotettu yhteys"); // Hae tulo- ja lähtövirrat BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ())); PrintWriter out = uusi PrintWriter (socket.getOutputStream ()); // Kirjoita otsikko asiakkaalle out.println ("Echo Server 1.0"); ulos. huuhtele (); // Kaiku linjat takaisin asiakkaalle, kunnes asiakas sulkee yhteyden tai saamme tyhjän rivin String line = in.readLine (); while (viiva! = null && viiva.pituus ()> 0) {out.println ("Kaiku:" + viiva); ulos. huuhtele (); rivi = in.readLine (); } // Sulje yhteys in.close (); out.close (); pistorasia.sulje (); System.out.println ("Yhteys suljettu"); } catch (Poikkeus e) {e.printStackTrace (); }}}