Morda ste že videli enega od številnih sistemov za klepet na Javi, ki so se pojavili v spletu. Po branju tega članka boste razumeli, kako delujejo - in vedeli, kako zgraditi svoj preprost sistem za klepet.
Ta preprost primer sistema odjemalca / strežnika je namenjen predstavitvi, kako graditi aplikacije z uporabo samo tokov, ki so na voljo v standardnem API-ju. Klepet za komunikacijo uporablja vtičnice TCP / IP in ga je mogoče enostavno vdelati v spletno stran. Za referenco nudimo stransko vrstico, ki razlaga komponente programskega omrežja Java, ki so pomembne za to aplikacijo. Če še vedno pospešujete, si najprej oglejte stransko vrstico. Če pa že dobro obvladate Javo, lahko skočite naravnost in se preprosto sklicujete na stransko vrstico.
Izdelava odjemalca za klepet
Začnemo s preprostim grafičnim odjemalcem za klepet. Za povezavo potrebujete dva parametra ukazne vrstice - ime strežnika in številko vrat. Vzpostavi povezavo z vtičnico in nato odpre okno z velikim izhodnim območjem in majhnim vhodnim območjem.
Vmesnik ChatClient
Ko uporabnik vnese besedilo v območje vnosa in pritisne tipko Return, se besedilo prenese na strežnik. Strežnik odmeva vse, kar pošlje odjemalec. Naročnik prikaže vse, kar je prejel od strežnika v izhodni regiji. Ko se več odjemalcev poveže z enim strežnikom, imamo preprost sistem za klepet.
Class ChatClient
Ta razred izvaja odjemalca za klepet, kot je opisano. To vključuje nastavitev osnovnega uporabniškega vmesnika, ravnanje z interakcijo uporabnika in prejemanje sporočil s strežnika.
uvoz java.net. *; uvoz java.io. *; uvoz java.awt. *; javni razred ChatClient razširja Frame implementira Runnable {// javni ChatClient (naslov niza, InputStream i, OutputStream o) ... // public void run () ... // javni logični handleEvent (Event e) ... // javni static void main (String args []) vrže IOException ...}
The ChatClient
razred se razširi Okvir
; to je značilno za grafično aplikacijo. Izvajamo Teče
vmesnik, da lahko začnemo Navoj
ki sprejema sporočila s strežnika. Konstruktor izvede osnovno nastavitev grafičnega uporabniškega vmesnika, teči ()
metoda prejema sporočila s strežnika, handleEvent ()
metoda obravnava interakcijo uporabnika in glavni ()
metoda izvede začetno omrežno povezavo.
zaščiten DataInputStream i; zaščiten DataOutputStream o; zaščiten izhod TextArea; zaščiten vnos TextField; zaščiten poslušalec niti; javni ChatClient (naslov niza, InputStream i, OutputStream o) {super (naslov); this.i = new DataInputStream (new BufferedInputStream (i)); this.o = nov DataOutputStream (nov BufferedOutputStream (o)); setLayout (novo BorderLayout ()); add ("Center", output = new TextArea ()); output.setEditable (false); add ("South", input = new TextField ()); paket (); show (); input.requestFocus (); poslušalec = nova nit (ta); listener.start (); }
Konstruktor ima tri parametre: naslov okna, vhodni tok in izhodni tok. The ChatClient
komunicira prek določenih tokov; ustvarjamo medpomnilniške tokove podatkov i in o, da zagotovimo učinkovite komunikacijske zmogljivosti na višji ravni prek teh tokov. Nato nastavimo naš preprost uporabniški vmesnik, sestavljen iz TextArea
proizvodnja in TextField
vhod. Postavimo in pokažemo okno ter zaženemo a Navoj
poslušalec, ki sprejema sporočila s strežnika.
public void run () {try {while (true) {String line = i.readUTF (); output.appendText (vrstica + "\ n"); }} catch (IOException ex) {ex.printStackTrace (); } končno {poslušalec = null; input.hide (); potrdi (); poskusite {o.close (); } catch (IOException ex) {ex.printStackTrace (); }}}
Ko nit poslušalca vstopi v način izvajanja, sedimo v neskončno branje zanke Vrvica
s iz vhodnega toka. Ko a Vrvica
prispe, ga dodamo izhodnemu območju in ponovimo zanko. An IOException
lahko pride do izgube povezave s strežnikom. V tem primeru natisnemo izjemo in izvedemo čiščenje. Upoštevajte, da bo to označeno z EOFException
Iz readUTF ()
metoda.
Za čiščenje najprej dodelimo referenco poslušalcu Navoj
do nič
; to pomeni preostali kodi, da je nit končana. Nato skrijemo vnosno polje in pokličemo potrdi ()
tako da je vmesnik spet postavljen, in zaprite Izhodni tok
o zagotoviti, da je povezava zaprta.
Upoštevajte, da vsa čiščenja izvajamo v a končno
klavzulo, zato se bo to zgodilo, če IOException
se zgodi tukaj ali pa se nit prisilno ustavi. Okna ne zapremo takoj; domneva se, da bo uporabnik morda želel prebrati sejo tudi po prekinitvi povezave.
javni logični handleEvent (dogodek e) {if ((e.target == input) && (e.id == Event.ACTION_EVENT)) {try {o.writeUTF ((String) e.arg); o.flush (); } catch (IOException ex) {ex.printStackTrace (); listener.stop (); } input.setText (""); vrni res; } else if ((e.target == this) && (e.id == Event.WINDOW_DESTROY)) {if (poslušalec! = null) listener.stop (); skrij (); vrni res; } vrnitev super.handleEvent (e); }
V handleEvent ()
, moramo preveriti dva pomembna dogodka uporabniškega vmesnika:
Prvi je akcijski dogodek v TextField
, kar pomeni, da je uporabnik pritisnil tipko Return. Ko ujamemo ta dogodek, zapišemo sporočilo v izhodni tok, nato pokličemo flush ()
da se zagotovi, da se pošlje takoj. Izhodni tok je DataOutputStream
, tako da lahko uporabimo writeUTF ()
poslati a Vrvica
. Če je IOException
zgodi se, da povezava ni uspela, zato ustavimo nit poslušalca; to bo samodejno izvedlo vsa potrebna čiščenja.
Drugi dogodek je uporabnik, ki poskuša zapreti okno. Programer mora poskrbeti za to nalogo; ustavimo nit poslušalca in skrijemo Okvir
.
public static void main (String args []) vrže IOException {if (args.length! = 2) vrže nov RuntimeException ("Sintaksa: ChatClient"); Vtičnica s = nova vtičnica (args [0], Integer.parseInt (args [1])); nov ChatClient ("Klepet" + args [0] + ":" + args [1], s.getInputStream (), s.getOutputStream ()); }
The glavni ()
metoda zažene odjemalca; če zagotovimo pravilno število argumentov, odpremo a Vtičnica
na določeni gostitelj in vrata, in ustvarimo ChatClient
priključen na tokove vtičnice. Ustvarjanje vtičnice lahko povzroči izjemo, ki bo zapustila to metodo in bo prikazana.
Izdelava večnitnega strežnika
Zdaj razvijamo klepetalniški strežnik, ki lahko sprejme več povezav in ki bo predvajal vse, kar bere od katere koli stranke. Branje in pisanje je težko Vrvica
s v obliki UTF.
V tem programu sta dva razreda: glavni razred, ChatServer
, je strežnik, ki sprejema povezave odjemalcev in jih dodeli novim objektom za obdelavo povezav. The ChatHandler
class dejansko opravlja poslušanje sporočil in njihovo oddajanje vsem povezanim odjemalcem. Ena nit (glavna nit) obravnava nove povezave, obstaja pa nit ( ChatHandler
razred) za vsako stranko.
Vsako novo ChatClient
se bo povezal z ChatServer
; to ChatServer
bo izročil povezavo novemu primerku ChatHandler
razred, ki bo prejemal sporočila od novega odjemalca. Znotraj ChatHandler
razred, se vodi seznam trenutnih upravljavcev; oddaja ()
metoda uporablja ta seznam za pošiljanje sporočila vsem povezanim ChatClient
s.
Class ChatServer
Ta razred se ukvarja s sprejemanjem povezav od odjemalcev in lansiranjem niti obdelave za njihovo obdelavo.
uvoz java.net. *; uvoz java.io. *; uvoz java.util. *; javni razred ChatServer {// javni ChatServer (int port) vrže IOException ... // javni statični void main (String args []) vrže IOException ...}
Ta razred je preprosta samostojna aplikacija. Dobavimo konstruktor, ki opravi vsa dejanska dela za razred, in a glavni ()
metoda, ki jo dejansko zažene.
javni ChatServer (int port) vrže IOException {ServerSocket server = new ServerSocket (port); while (true) {Odjemalec vtičnice = server.accept (); System.out.println ("Sprejeto iz" + client.getInetAddress ()); ChatHandler c = nov ChatHandler (odjemalec); c.start (); }}
Ta konstruktor, ki izvaja vsa dela strežnika, je dokaj preprost. Ustvarimo a ServerSocket
in nato sedite v zanki in sprejemate stranke z sprejme ()
metoda ServerSocket
. Za vsako povezavo ustvarimo nov primerek datoteke ChatHandler
razred, mimo novega Vtičnica
kot parameter. Ko smo ustvarili ta vodnik, ga začnemo s svojim začetek ()
metoda. S tem se zažene nova nit za obdelavo povezave, tako da lahko naša glavna strežniška zanka še naprej čaka na nove povezave.
public static void main (String args []) vrže IOException {if (args.length! = 1) vrže nov RuntimeException ("Sintaksa: ChatServer"); novi ChatServer (Integer.parseInt (args [0])); }
The glavni ()
metoda ustvari primerek datoteke ChatServer
, kot parameter posreduje vrata ukazne vrstice. To so vrata, na katera se bodo stranke povezale.
Razred ChatHandler Ta razred se ukvarja z obdelavo posameznih povezav. Od stranke moramo prejeti sporočila in jih ponovno poslati vsem ostalim povezavam. Vzdržujemo seznam povezav v a statično
Vektor
.
uvoz java.net. *; uvoz java.io. *; uvoz java.util. *; javni razred ChatHandler razširi nit {// javni ChatHandler (vtičnice) vrže IOException ... // public void run () ...}
Podaljšujemo Navoj
razred, da dovoli ločeni niti za obdelavo povezanega odjemalca. Konstruktor sprejme a Vtičnica
na katero se vežemo; teči ()
metoda, ki jo pokliče nova nit, izvede dejansko obdelavo odjemalca.
zaščitena vtičnica s; zaščiten DataInputStream i; zaščiten DataOutputStream o; javni ChatHandler (vtičnice) vrže IOException {this.s = s; i = nov DataInputStream (nov BufferedInputStream (s.getInputStream ())); o = nov DataOutputStream (nov BufferedOutputStream (s.getOutputStream ())); }
Konstruktor ohrani sklic na vtičnico odjemalca in odpre vhodni in izhodni tok. Spet uporabljamo medpomnilniške tokove podatkov; ti nam zagotavljajo učinkovite V / I in metode za sporočanje podatkovnih vrst na visoki ravni - v tem primeru Vrvica
s.
zaščiteni statični obdelovalci vektorjev = new Vector (); javna void run () {try {handlers.addElement (this); while (true) {String msg = i.readUTF (); oddajanje (sporočilo); }} catch (IOException ex) {ex.printStackTrace (); } končno {handlers.removeElement (this); poskusite {s.close (); } catch (IOException ex) {ex.printStackTrace (); }}} // zaščitena statična void oddaja (sporočilo v nizu) ...
The teči ()
metoda vstopi v naš nit. Najprej dodamo svojo nit v Vektor
od ChatHandler
vodniki. Vodniki Vektor
vodi seznam vseh trenutnih upravljavcev. Je statično
spremenljivka in tako obstaja en primerek Vektor
za celoto ChatHandler
razreda in vseh njegovih primerov. Tako vsi ChatHandler
lahko dostopate do seznama trenutnih povezav.
Upoštevajte, da je za nas zelo pomembno, da se kasneje odstranimo s tega seznama, če naša povezava ne uspe; v nasprotnem primeru nam bodo vsi drugi upravljavci poskušali pisati, ko bodo oddajali informacije. Ta vrsta primerov, kjer je nujno, da se dejanje izvede po zaključku dela kode, je glavna uporaba poskusite ... končno
konstruirati; zato vse svoje delo opravljamo v okviru poskusite ... ulovite ... končno
konstruirati.
Telo te metode prejme sporočila od odjemalca in jih znova pošlje vsem ostalim odjemalcem, ki uporabljajo oddaja ()
metoda. Ko zanka izstopi, bodisi zaradi branja izjeme od odjemalca bodisi zaradi zaustavitve te niti, se končno
klavzula zagotovljena za izvedbo. V tem stavku odstranimo svojo nit s seznama upravljavcev in zapremo vtičnico.
zaščitena statična void oddaja (sporočilo v nizu) {sinhronizirano (handlers) {Enumeration e = handlers.elements (); while (e.hasMoreElements ()) {ChatHandler c = (ChatHandler) e.nextElement (); poskusite {sinhronizirano (c.o) {c.o.writeUTF (sporočilo); } c.o.flush (); } ulov (IOException ex) {c.stop (); }}}}
Ta metoda pošilja sporočilo vsem strankam. Najprej sinhroniziramo na seznamu upravljavcev. Nočemo, da se ljudje pridružijo ali odidejo, medtem ko zapeljemo, če poskušamo oddajati komu, ki ne obstaja več; to prisili stranke, da počakajo, da končamo s sinhronizacijo. Če mora strežnik prenašati posebej velike obremenitve, bomo morda zagotovili bolj natančno sinhronizacijo.
V tem sinhroniziranem bloku dobimo Naštevanje
sedanjih upravljavcev. The Naštevanje
class ponuja priročen način za ponavljanje vseh elementov a Vektor
. Naša zanka preprosto zapiše sporočilo v vsak element datoteke Naštevanje
. Upoštevajte, da če pride do izjeme med pisanjem v ChatClient
, nato pokličemo strankino stop ()
metoda; to ustavi naročnikovo nit in zato izvede ustrezno čiščenje, vključno z odstranjevanjem odjemalca iz upravljavcev.