Java chat sistem |
Ivan Mitrović |
Web je višekorisničko okruženje, ali ga Java vodi korak dalje: uz malo programiranja, možete interaktivno razmenjivati informacije sa drugom čitaocima neke Web strane. Ograničimo se, za početak, na prenos tekstualnih poruka i isprobajmo Chat u Javi... |
Jedna od najinteresantnijih stvari koje Java nudi programerima jeste mogućnost stvaranja
višekorisničkog okruženja. Korisnici mogu da razmenjuju informacije, povezani preko server
aplikacije koja je pokrenuta na hostu čija je adresa dostupna - akcije jednog korisnika
prikazuju se na ekranima ostalih. Ovakvo klijent/server višekorisničko okruženje pruža ogromne
mogućnosti za izradu servisa kakvi se pre upotrebe Jave nisu mogli ni zamisliti.
Za funkcionisanje chat -a treba isprogramirati server i klijent. Server aplikacija mora da
omogući prihvatanje poziva više klijenata na isti port, prijem informacija od klijenata i
slanje primljenih informacija svim klijentima odnosno samo određenom klijentu. Klijent mora da
neprestano "osluškuje" server i prikazuje poruke servera u obliku koji je prihvatljiv za
korisnika, a takođe i da obezbedi obradu akcija korisnika: slanje poruka serveru, razmenu
privatnih poruka, napuštanje chata itd.
Klijent
Dok je za server jasno da mora biti aplikacija, klijent nas stavlja pred dilemu: aplet ili
aplikacija? Izbor zavisi od servisa koji treba pružiti, okruženja u kome će se servis
izvršavati, pa i od afiniteta samog programera. Aplet je uklopljen u Web okruženje i koristi
sve njegove pogodnosti - ako želite javni chat na svom Internet ili intranet sajtu, izrada
klijent apleta se podrazumeva. Aplet ima ograničenja u bezbedonosnom smislu: konekcija je
ograničena na server koji "trči" na hostu na kome je aplet postavljen, dok je Java aplikacija
oslobođena tih stega. Zbog čitave euforije koja ovih dana prati Web , ovde ćemo se osvrnuti na
izradu klijent apleta koji se jednostavno ugrađuje u HTML stranu i omogućava nesmetanu
komunikaciju korisnika Internet sajta ili zaposlenih u firmi čiji su browser -i usmereni na
intranet prezentaciju.
Pre nego što počnemo da programiramo, treba da projektujemo zahteve koji se postavljaju pred
klijenta. Taj posao zavisi od potreba, želja, pa i od umeća programera. Klijent koji mi pravimo
omogućava registraciju korisnika, tj. unos imena pod kojim će korisnik biti poznat ostalim
učesnicima u razgovoru, održavanje liste korisnika, odnosno mogućnost da svaki klijent zna ko
je u chat -u, slanje poruka koje će biti vidljive svim korisnicima i slanje privatnih poruka,
odnosno poruka koje će videti samo određeni korisnik odabran sa liste.
Pošto su zahtevi poznati, treba osmisliti grafički interfejs, recimo kao na slici 1. Poruke
koje server šalje ispisuju se u kontroli tipa TextArea koja dominira apletom. Poruke se unose
u TextField na dnu apleta, a lista korisnika se prati u kontroli tipa List s desne strane.
Kod kojim sve to postižemo izgleda ovako:
setLayout (new BorderLayout ()); add ("East", list1 = new List ()); add ("Center", out = new TextArea ()); out.setEditable (false); add("South", in = new TextField ()); in.requestFocus (); |
public void run () { try { while (true) { String line = i.readUTF (); if(!line.startsWith("<<") & !line.startsWith("*") & !line.startsWith("Napusta") & !line.startsWith("To ime") ) { list1.addItem(line); } |
if (line.startsWith("<<") | line.startsWith("*")) { out.appendText (line + "\n"); } |
if(line.startsWith("Napusta")) { String line1 = line.substring(7,8); int k = Integer.parseInt(line1); list1.delItem(k); } |
finally { runner = null; in.hide (); validate (); try { o.close (); } catch (IOException ex) { ex.printStackTrace (); } } |
try { o.writeUTF ("* Privatna poruka " + lin + ", salje " + i1 + "Glasi:" + ' ' + in.getText()); o.flush (); } catch (IOException ex) { ex.printStackTrace(); runner.stop (); } out.appendText("<<" + i1 + "-->>" + lin + ">>" + " " + in.getText() + "\n"); in.setText(""); } |
Server
Server koji je multithreaded (podržava više niti) osluškuje na portu 9999 i prihvata nove klijente. Informacije od svakog klijenta primaju se u posebnim nitima ( Thread ). Server prihvata svakog novog klijenta i predaje ga klasi Glavna , čija je podklasa Thread . Klijent se zatim upisuje u vektor koji je klase vector (omogućava dinamičko dodeljivanje elemenata), a ime klijenta se upisuje u vector vektor1.
while (true) { Socket klijent = server.accept (); System.out.println ("Poziv od " + klijent.getInetAddress ()); Glavna c = new Glavna (klijent); c.start (); } |
Zaključak
Projektovanje klijent/server sistema u Javi znatno je lakše nego programiranje takvih sistema u
ostalim programskim jezicima. Java API ima sve klase neophodne za pisanje programa koji
ostvaruju komunikaciju preko mreže koristeći TCP/IP mrežni protokol. Java klijent/server
sistemi mogu da pokriju čitav spektar servisa a za šta će se upotrebiti zavisi samo od ideje i
umeća programera. Nije teško, recimo, napraviti sistem koji će omogućiti igranje šaha preko
Interneta - suštinska razlika je samo u programiranju adekvatnog klijenta i servera koji će
razlikovati zaglavlja poruka koje se razmenjuju.
Ovde prikazani chat sistem može se po volji poboljšavati, naprimer otvaranjem više "soba"
koje se bave različitim temama. To ostavljam vama za dalje istraživanje, a ja ću vam pomoći
kada kažem da za svaku novootvorenu "sobu" treba na serveru dinamički dodeliti novi port.
Naravno, ako ste umorni od pisanja Java programa, svratite na Web stranu časopisa "PC" (
www.pcpress.co.yu/chat ) i popričajte sa prijateljima preko Web -a...
Slika 2: Klijent.java |
// Klijent.java Ivan Mitrovic Jun, 1997. import java.net.*; import java.io.*; import java.awt.*; public class Klijent extends java.applet.Applet implements Runnable { Socket s; protected DataInputStream i; protected DataOutputStream o; protected TextArea out; protected TextField in; protected List list1; protected Thread runner; String Imehosta, i1; int ind; public void init() { ind = 0; try { Imehosta = InetAddress.getLocalHost().toString(); } catch(Exception e); setLayout (new BorderLayout ()); add ("East", list1 = new List ()); add ("Center", out = new TextArea ()); out.setEditable (false); out.appendText(" ********* Java Chat sistem *********" + "\n"); out.appendText("Autor: Mitrovic Ivan mivan@EUnet.yu" + "\n"); out.appendText("Jun 1997." + "\n"); out.appendText(" " + "\n"); out.appendText("Unesi ime:" + "\n"); add("South", in = new TextField ()); in.requestFocus (); } public void stop() { if ((runner != null) && runner.isAlive()) { runner.stop(); runner = null; destroy(); } } public void run () { try { while (true) { String line = i.readUTF (); if (!line.startsWith("<<") & !line.startsWith("*") & !line.startsWith("Napusta") & !line.startsWith("To ime") ) { list1.addItem(line); } if (line.startsWith("<<") | line.startsWith("*")) { out.appendText (line + "\n"); } if (line.startsWith("Napusta")) { String line1 = line.substring(7,8); int k = Integer.parseInt(line1); list1.delItem(k); } if(line.startsWith("To ime")) { out.appendText(line + "\n"); String line2 = line.substring(44); i1 = line2; } } } catch (IOException ex) { ex.printStackTrace (); } finally { runner = null; in.hide (); validate (); try { o.close (); } catch (IOException ex) { ex.printStackTrace (); } } } public boolean handleEvent (Event e) { if ((e.target == in) && (e.id == Event.ACTION_EVENT)) { if (ind == 1) { try { o.writeUTF ("<<" + i1 + ">>" + ' ' + (String) e.arg); o.flush (); } catch (IOException ex) { ex.printStackTrace(); runner.stop (); } } if (ind == 0) { i1 = (String) e.arg; ind = 1; try { getAppletContext().showStatus("Uspostavljam vezu sa hostom 194.247.206.194..."); s = new Socket ("194.247.206.194", 9999); i = new DataInputStream (new BufferedInputStream (s.getInputStream())); o = new DataOutputStream (new BufferedOutputStream(s.getOutputStream())); } catch(Exception e1) { getAppletContext().showStatus(e1.toString()); } runner = new Thread (this); runner.start (); out.replaceText(" ",0,150); getAppletContext().showStatus(" "); try { o.writeUTF (i1); o.flush (); } catch (IOException ex) { ex.printStackTrace(); runner.stop (); } } in.setText (""); return true; } else if (e.target instanceof List & e.id == Event.LIST_SELECT) { String lin = list1.getSelectedItem(); try { o.writeUTF ("* Privatna poruka " + lin + ", salje " + i1 + "Glasi:" + ' ' + in.getText()); o.flush (); } catch (IOException ex) { ex.printStackTrace(); runner.stop (); } out.appendText("<<" + i1 + "-->>" + lin + ">>" + " " + in.getText() + "\n"); in.setText(""); } return super.handleEvent (e); } } |
Slika 3 |
synchronized (vektor) { Enumeration e = vektor.elements (); while (e.hasMoreElements ()) { Glavna c = (Glavna) e.nextElement (); try { synchronized (c.o) { c.o.writeUTF (poruka); } c.o.flush (); } catch (IOException ex) { c.stop (); } } } |
Slika 4 |
finally { int k = vektor.indexOf(this); String ime = vektor1.elementAt(k).toString(); vektor.removeElement (this); vektor1.removeElementAt(k); synchronized (vektor) { Enumeration e = vektor.elements (); while (e.hasMoreElements ()) { Glavna c = (Glavna) e.nextElement (); try { synchronized (c.o) { c.o.writeUTF ("Napusta" + k); } c.o.flush (); } catch (IOException ex) { c.stop (); } } } |
Server.java |
// Server.java Ivan Mitrovic, jun 1997. import java.net.*; import java.io.*; import java.util.*; public class Server { String ime; public Server (int port) throws IOException { ServerSocket server = new ServerSocket (port); while (true) { Socket klijent = server.accept (); System.out.println ("Poziv od " + klijent.getInetAddress ()); Glavna c = new Glavna (klijent); c.start (); } } public static void main (String args[]) throws IOException { new Server (9999); } } class Glavna extends Thread { protected Socket s; protected DataInputStream i; protected DataOutputStream o; int ind,ind2,ind3; public Glavna (Socket s) throws IOException { this.s = s; i = new DataInputStream (new BufferedInputStream (s.getInputStream ())); o = new DataOutputStream (new BufferedOutputStream (s.getOutputStream ())); } protected static Vector vektor = new Vector(); protected static Vector vektor1 = new Vector(); public void run () { try { ind2 = 0; ind = 0; while (true) { ind3 = 0; String msg = i.readUTF (); if (!msg.startsWith("<<") & !msg.startsWith("*")) { while(vektor1.indexOf(msg) >> -1) { ind2 = 1; msg = msg + "*"; } if (vektor1.indexOf(msg) == -1) { vektor.addElement (this); vektor1.addElement(msg); Glavna c = (Glavna) vektor.lastElement (); for (int i = 0; i << vektor1.size()-1;i ++) { String msg1 = vektor1.elementAt(i).toString(); try { synchronized (c.o) { c.o.writeUTF (msg1); } c.o.flush (); } catch (IOException ex) { c.stop (); } } if (ind2 ==1) { Glavna c1 = (Glavna) this; try { synchronized (c1.o) { c1.o.writeUTF ("To ime je vec u upotrebi, promenio sam ga u " + vektor1.lastElement().toString()); } c1.o.flush (); } catch (IOException ex) { c1.stop (); } } salji("***** " + vektor1.lastElement().toString() + " se prikljucuje razgovoru *****"); msg = vektor1.lastElement().toString(); ind = 1; } } if(msg.startsWith("***** Privatna")) { String line3 = msg.substring(22,msg.indexOf(",")); Glavna c2 = (Glavna) vektor.elementAt(vektor1.indexOf(line3)); int pol = msg.indexOf("salje") + 6 ; int pol1 = msg.indexOf("Glasi:"); try { synchronized (c2.o) { c2.o.writeUTF ("***** Privatna poruka od korisnika sa imenom " + msg.substring(pol,pol1) + "\n" + "GLASI: " + msg.substring(pol1+6)); } c2.o.flush (); } catch (IOException ex) { c2.stop (); } ind3 = 1; } if (ind == 1 & ind3 == 0) { salji (msg); } } } catch (IOException ex) { ex.printStackTrace (); } finally { int k = vektor.indexOf(this); String ime = vektor1.elementAt(k).toString(); vektor.removeElement (this); vektor1.removeElementAt(k); synchronized (vektor) { Enumeration e = vektor.elements (); while (e.hasMoreElements ()) { Glavna c = (Glavna) e.nextElement (); try { synchronized (c.o) { c.o.writeUTF ("Napusta" + k); } c.o.flush (); } catch (IOException ex) { c.stop (); } } } synchronized (vektor) { Enumeration e = vektor.elements (); while (e.hasMoreElements ()) { Glavna c = (Glavna) e.nextElement (); try { synchronized (c.o) { c.o.writeUTF ("* " + ime + " napusta razgovor *"); } c.o.flush (); } catch (IOException ex) { c.stop (); } } } try { s.close (); } catch (IOException ex) { ex.printStackTrace(); } } } protected static void salji (String poruka) { synchronized (vektor) { Enumeration e = vektor.elements (); while (e.hasMoreElements ()) { Glavna c = (Glavna) e.nextElement (); try { synchronized (c.o) { c.o.writeUTF (poruka); } c.o.flush (); } catch (IOException ex) { c.stop (); } } } } } |
|