Aplet DwaZegary ilustruje niekt�re mo�liwo�ci Javy takie, jak: wielow�tkowo��, wsp�praca z sieci� Internet oraz z przegl�dark�, w kt�rej wy�wietlana jest strona WWW zawieraj�ca aplet. Wykorzystano tak�e poj�cie strumieni oraz klasy i komponenty AWT, do kt�rych nale��: panele, przyciski, zdarzenia, zarz�dcy widok�w.
W aplecie tym ��czymy si� z serwerem, z kt�rego zosta�a za�adowana strona go zawieraj�ca. Z tego serwera odczytujemy dat� i czas (us�uga 'dtime'), nast�pnie odczytujemy dat� i czas na naszym komputerze. Te informacje s� wykorzystane przy tworzeniu dwu w�tk�w, odpowiadaj�cych za: rysowanie odpowiednio: zegara wy�wietlaj�cego czas odczytany z serwera i zegara wy�wietlaj�cego czas lokalny. Dodatkowo u do�u okna znajduje si� przycisk, po naci�ni�ciu kt�rego mamy mo�liwo�� wys�ania poczty email, dzi�ki wykorzystaniu w�a�ciwo�ci przegl�darki. Gdy w u�ytej tu metodzie showDocument (opis, patrz: Przyk�ad 2.44):
showDocument(new URL("mailto:arturt@friko.onet.pl"),"_self");
zmienimy pierwszy parametr na adres strony WWW, naci�ni�cie przycisku spowoduje jej wy�wietlenie w przegl�darce.
Apletu w trakcie dzia�ania przedstawia poni�sza ilustracja:
Ilustracja 4-1Wygl�d apletu DwaZegary
Aplet korzysta z us�ugi 'dtime', us�uga ta umo�liwia sprawdzenie aktualnego czasu i daty na komputerze, z kt�rym sie po��czyli�my.
Dok�adny opis us�ugi mo�na znale�� w dokumencie RFC867. Og�lnie, korzysta ona z portu nr 13. Komunikacja polega na nawi�zaniu po��czenia z serwerem i przes�aniu przez niego informacji. Potem nast�puje przerwanie po��czenia.
Tekst apletu zamieszczono poni�ej:
import java.util.Date; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; public class DwaZegary extends java.applet.Applet implements Runnable { // program napisano tak, aby �atwo mo�na by�o zwi�kszy� liczb� // rysowanych zegar�w static int m_nLiczbaZegarow = 2; Date daty[]; WatekZegara zegary[]; Thread watki[]; Thread watekGlowny; int m_nLiczbaWatkowNaStarcie; //adresy, �r�d�a daty i czasu public String zrodloDanych[] = {"friko.onet.pl", "czas lokalny"}; public void init() { // u�yjemy tej zmiennej p�niej aby sprawdzi� czy wszystkie // w�tki zosta�y zabite m_nLiczbaWatkowNaStarcie = Thread.activeCount(); // ustawienie zarz�dcy rozmieszczenia; zegary b�d� dodawane // na prawo od ostatniego dodanego setLayout(new BorderLayout()); // utworzenie panelu zawieraj�cego zegary Panel panel = zegaryGridLayoutPanel(); // utworzenie tablic zawieraj�cych: // 1 w�tki rysuj�ce zegary, zegary = new WatekZegara[m_nLiczbaZegarow]; // 2 w�tki kontroluj�ce wykonanie w�tk�w typu WatekZegara, watki = new Thread[m_nLiczbaZegarow]; // 3 informacj� o czasie i dacie daty = new Date[m_nLiczbaZegarow]; // w tym bloku, czytane s� dane z serwer�w (oraz czas lokalny) for (int numerSerwera = 0; numerSerwera < m_nLiczbaZegarow; numerSerwera++) { if(zrodloDanych[numerSerwera].compareTo("czas lokalny") != 0) { try { Socket gniazdko = new Socket(zrodloDanych[numerSerwera] ,13 ); DataInputStream dis = new DataInputStream(gniazdko.getInputStream()); daty[numerSerwera]= new Date(dis.readLine()); gniazdko.close(); } catch(IOException ioe) { zrodloDanych[numerSerwera] = "blad przy polaczeniu z "+zrodloDanych[numerSerwera]; daty[numerSerwera] = new Date(97,01,02,11,59,59); } catch (Exception e) { zrodloDanych[numerSerwera] = "blad dla "+zrodloDanych[numerSerwera]; daty[numerSerwera] = new Date(97,01,02,11,59,59); } finally { // inicjalizacja w�tk�w rysuj�cych zegary i dodanie // zegara do panelu inicjujZegar(numerSerwera, panel); } } else { // inicjalizacja pozosta�ych zegar�w daty[numerSerwera] = new Date(); inicjujZegar(numerSerwera, panel); } } add("North",panel); Button wyslanieWiadomosci = new Button("Autor: Artur Tyloch (arturt@friko.onet.pl)"); add("Center",wyslanieWiadomosci); wyslanieWiadomosci.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { try { getAppletContext().showDocument( new URL("mailto:arturt@friko.onet.pl"),"_self"); } catch(Exception e){} } } ); } Panel zegaryGridLayoutPanel() { Panel tmpPanel = new Panel(); tmpPanel.setLayout(new GridLayout(1,m_nLiczbaZegarow)); return tmpPanel; } // w metodzie tej tworzymy nowy w�tek dla ka�dego zegara // i dodajemy go do panelu void inicjujZegar(int x, Panel zegarPanel) { zegary[x]=new WatekZegara(daty[x], true, zrodloDanych[x]); zegary[x].resize(size().width,(int)(size().height/1.2)); zegarPanel.add(zegary[x]); watki[x]=new Thread(zegary[x]); } public void start() { // uruchomienie wszystkich w�tk�w zegar�w for (int x = 0; x < m_nLiczbaZegarow; x++) watki[x].start(); // utworzenie w�tku g��wnego, u�ywanego do monitorowania // stanu zegar�w watekGlowny= new Thread (this); watekGlowny.start(); } public void stop() { watekGlowny.stop(); } public void run() { // wykonanie p�tli do czasu a� wszystkie zegary zako�cz� // swoje dzia�anie while(Thread.activeCount() > m_nLiczbaWatkowNaStarcie+2) { try { watekGlowny.sleep(10); repaint(); } catch (InterruptedException e) { System.out.println("watekGlowny was interrupted"); } } stop(); destroy(); } }
W klasie WatekZegara zdefiniowano metody odpowiedzialne za rysowanie pojedynczego zegara:
import java.util.*; import java.awt.Font; import java.awt.Graphics; import java.awt.Color; public class WatekZegara extends java.awt.Canvas implements Runnable { // wsp�rzedne rysowanych wskaz�wek private int m_nOstatnieXS=0, m_nOstatnieYS=0, m_nOstatnieXM=0, m_nOstatnieYM=0, m_nOstatnieXH=0, m_nOstatnieYH=0; // ostatnio wy�wietlany czas i data private String m_OstatniaData = null; // r�nica pomi�dzy czasem lokalnym a czasem na serwerze private long m_lRoznica = 0; // pole danych okre�laj�ce czy wy�wietlamy czas lokalny, // czy czas serwera private boolean m_bZdalne; private String m_informacja; WatekZegara(Date d, boolean Zdalne, String info) { Date localD = new Date(); if ( localD != d) m_lRoznica = localD.getTime() - d.getTime(); m_OstatniaData = d.toLocaleString(); m_bZdalne = Zdalne; m_informacja = info; m_nOstatnieXS=70; m_nOstatnieYS=m_nOstatnieXS; m_nOstatnieXM=m_nOstatnieXS; m_nOstatnieYM=m_nOstatnieXS; m_nOstatnieXH=m_nOstatnieXS; m_nOstatnieYH=m_nOstatnieXS; } public void run() { while (true) { repaint(); // u�pienie w�tku, aby umo�liwi� przerysowania apletu try { Thread.currentThread().sleep(1000); } catch (InterruptedException e){ } } } public void update(Graphics g) { // nie ma efektu mrugania (domniemana metoda update // czy�ci pulpit kolorem t�a, a nast�pnie rysuje aplet), // tu w metodzie paint stare wskaz�wki s� zamazywane i // nie ma k�opotu z mruganiem rysowanego obrazu zegar�w paint(g); } public synchronized void paint(Graphics g) { Date dat = new Date(); if (m_bZdalne) dat = new Date(dat.getTime()-m_lRoznica); rysujZegar(dat.getSeconds(), dat.getMinutes(), dat.getHours(), size().width/2, 70, dat.toLocaleString(), g); g.setFont(new Font("Helvetica", Font.BOLD, 12)); g.drawString("Czas:",20 , 165); g.drawString(m_informacja,20 , 185); g.setFont(new Font("Courier", Font.ITALIC, 10)); g.drawString("autor: Artur Tyloch",20 , 195); g.draw3DRect(2,2,size().width - 4,size().height - 4,true); g.drawRoundRect(5,5,size().width - 10,size().height - 10, 45, 50); } synchronized private void rysujZegar(int s, int m, int h, int xcenter, int ycenter, String dzis, Graphics g) { int xh, yh, xm, ym, xs, ys; xs = (int)(Math.cos(s * 3.14f/30 - 3.14f/2) * 45 + xcenter); ys = (int)(Math.sin(s * 3.14f/30 - 3.14f/2) * 45 + ycenter); xm = (int)(Math.cos(m * 3.14f/30 - 3.14f/2) * 40 + xcenter); ym = (int)(Math.sin(m * 3.14f/30 - 3.14f/2) * 40 + ycenter); xh = (int)(Math.cos((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + xcenter); yh = (int)(Math.sin((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + ycenter); // Rysowanie ko�a i liczb g.setFont(new Font("Courier", Font.BOLD, 14)); g.setColor(Color.blue); g.drawOval(xcenter - 50,ycenter -50 ,100,100); g.setColor(Color.yellow); g.fillOval(xcenter - 45,ycenter -45 ,90,90); g.setColor(Color.darkGray); g.drawString("9",xcenter-45,ycenter+3); g.drawString("3",xcenter+40,ycenter+3); g.drawString("12",xcenter-5,ycenter-37); g.drawString("6",xcenter-3,ycenter+45); // wymazanie, gdy zachodzi taka potrzeba i przerysowanie g.setColor(Color.yellow/*getBackground()*/); if (xs != m_nOstatnieXS || ys != m_nOstatnieYS) { g.drawLine(xcenter, ycenter, m_nOstatnieXS, m_nOstatnieYS); g.setColor(getBackground()); g.drawString(m_OstatniaData, 20 , ycenter + 75); g.setColor(Color.yellow/*getBackground()*/); } if (xm != m_nOstatnieXM || ym != m_nOstatnieYM) { g.drawLine(xcenter, ycenter-1, m_nOstatnieXM, m_nOstatnieYM); g.drawLine(xcenter-1, ycenter, m_nOstatnieXM, m_nOstatnieYM); } if (xh != m_nOstatnieXH || yh != m_nOstatnieYH) { g.drawLine(xcenter, ycenter-1, m_nOstatnieXH, m_nOstatnieYH); g.drawLine(xcenter-1, ycenter, m_nOstatnieXH, m_nOstatnieYH); } g.setColor(Color.darkGray); g.drawString(dzis, 20, ycenter + 75); g.drawLine(xcenter, ycenter, xs, ys); g.setColor(Color.blue); g.drawLine(xcenter, ycenter-1, xm, ym); g.drawLine(xcenter-1, ycenter, xm, ym); g.drawLine(xcenter, ycenter-1, xh, yh); g.drawLine(xcenter-1, ycenter, xh, yh); m_nOstatnieXS=xs; m_nOstatnieYS=ys; m_nOstatnieXM=xm; m_nOstatnieYM=ym; m_nOstatnieXH=xh; m_nOstatnieYH=yh; m_OstatniaData = dzis; } }
W aplecie MailAplet pokazano wykorzystanie protoko�u SMTP (ang. Simple Mail Transfer Protocol) do wys�ania poczt� e-mail z apletu pod zadany adres.
Po wczytaniu przez przegl�dark� strony WWW zawieraj�cej ten aplet, wysy�any jest list pod adres okre�lony przez pole danych o nazwie adresat. W polu 'Subject' e-mail'a wysy�ana jest informacja o adresie IP osoby przegl�daj�cej stron� WWW. Do pobrania adresu IP u�yto metody statycznej getLocalHost klasy InetAddress.
Dok�adny opis protoko�u mo�na znale�� w dokumencie RFC821. Og�lnie, korzysta on z portu nr 25.
Opis komunikacji:
Klient: MAIL <SPACJA> FROM:<adres nadawcy> <CRLF> Serwer: 250 <komunikat> K: RCPT <SPACJA> TO:<adres odbiorcy> <CRLF> S: 250 <komunikat> K: DATA <CRLF> S: 354 <komunikat2> K: Jakas przykladowa tresc listu .... K: ... itd. itd. itd. K: <CRLF>.<CRLF> S: 250 <komunikat>
W programie nie interesuje si� tym, co wysy�a serwer, bo zak�adam, ze podaje prawdziwe dane. Poni�ej przedstawiono kod apletu:
import java.applet.*; import java.awt.*; import java.io.*; import java.net.*; import java.util.*; public class MailAplet extends Applet { String m_mojGosc = null; String adresat = "arturt@priv.onet.pl"; public void init() { resize(320, 40); try { System.out.println("Przygotowanie listu\n"); Socket socket = new Socket(getCodeBase().getHost(),25); //odpowiedzi serwera mo�na sprawdzi�, gdy zadeklarujemy: //DataInputStream dis = // new DataInputStream(socket.getInputStream()); // i b�dziemy je interpretowa� DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeBytes("MAIL FROM:<zieloni@uop.warszawa.gov.pl>\n"); dos.writeBytes("RCPT TO:<"+adresat+">\n"); dos.writeBytes("DATA\r\n"); try { m_mojGosc=InetAddress.getLocalHost().toString(); } catch (UnknownHostException e) { m_mojGosc=e.toString(); } dos.writeBytes("Subject: GOSC: "+m_mojGosc+"\n\n"); dos.writeBytes("Dzis odwiedzil:\r\n"); dos.writeBytes(m_mojGosc+"\r\n"); dos.writeBytes(".\r\n.\n\n.\nQUIT"); dos.flush(); System.out.println("List zostal wyslany"); socket.close(); } catch(IOException e) { System.out.println("BLAD !!!"); } } // wy�wietlenie w oknie apletu informacji o wys�aniu e-mail'a public void paint(Graphics g) { g.drawString("Czesc: "+m_mojGosc, 10, 20); g.drawString("Mail z informacja o twojej wizycie zostal" + " wyslany do: "+adresat, 10, 30); } }
Zauwa�my, ze mo�na w ten spos�b wys�a� list jako "ktokolwiek". Wystarczy tylko w "MAIL FROM:<adres>" poda� dowolny (nawet nieistniej�cy) adres. Tym sposobem mo�na podszy� si� pod ka�dego !
A oto, kilka nag��wk�w (pole Subject) list�w jakie otrzyma�em, po umieszczeniu apletu na stronie WWW "http://friko.onet.pl/po/arturt/":
GOSC: robert/195.116.127.24 GOSC: pcjura.comarch.pl/195.116.125.114 GOSC: fornax/150.254.25.38 GOSC: wks620.inform.pucp.edu.pe/200.16.7.180 GOSC: w014-3.ppcor.org.pl/190.59.76.23 GOSC: lala.waw.ids.edu.pl/195.117.3.20 GOSC: imul-043.uni.lodz.pl/193.59.60.56 GOSC: ds3pc94.pol.lublin.pl/194.92.19.94 GOSC: quake.tx.iex.com/192.153.191.251 GOSC: ppp.sylaba.poznan.pl/150.254.152.163 GOSC: Dolar.it.com.pl/195.116.134.101 GOSC: parkds.hscom.co.kr/150.30.50.32
Na podobnych zasadach mo�na napisa� w Javie ka�d� us�ug� sieciow�.
Pisanie sieciowych aplikacji w Javie jest bardzo proste. Java dostarcza pakiet java.net, w kt�rym s� zdefiniowane wszystkie niezb�dne klasy do obs�ugi komunikacji po��czeniowej (TCP) i bezpo��czeniowej (UDP), zar�wno dla aplikacji klienckich jak i serwerowych.