Proz S14 id 402991 Nieznany

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 1

14. Komunikacja rozproszona

– gniazdka, RMI

14.1 Pakiet

java.net

14.2 Mechanizm gniazdek TCP

14.3 Przykład aplikacji klient-serwer

14.4 RMI – model DOA

14.5 Przykład aplikacji rozproszonej

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 2

14.1 Pakiet java.net - wprowadzenie

1) Elementy programowania sieciowego

Aplikacje programowe w Javie korzystaj

ą

z protokółów warstwy

transportowej sieci:



„Transmission Control Protocol” (TCP) lub



„User Datagram Protocol” (UDP).



TCP

to poł

ą

czeniowy, niezawodny protokół typu point-to-point – dane

nadchodz

ą

w kolejno

ś

ci wysłania.

Z TCP korzystaj

ą

takie aplikacje, jak Hypertext Transfer Protocol

(HTTP), File Transfer Protocol (FTP), Telnet.



UDP

to bezpoł

ą

czeniowy protokół niezale

ż

nego przesyłania pakietów

danych (tzw. datagramy).
Korzystaj

ą

z niego programy nie wymagaj

ą

ce gwarantowanych

poł

ą

cze

ń

, np. serwer zegara, program ping.

Porty

- logiczne punkty wej

ś

cia do aplikacji pracuj

ą

cych na danym

komputerze, doł

ą

czonym do sieci.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 3

Dane przekazywane przez Internet posiadaj

ą

adres swojego

przeznaczenia:



adres komputera -

32-bitowy adres IP

,



adres portu -

16-bitowy numer portu

.

W komunikacji według protokółu TCP, serwer zwi

ą

zuje swoje

gniazdko

z okre

ś

lonym portem – rejestruje si

ę

pod okre

ś

lonym portem. Równie

ż

w protokóle UDP

pakiety kierowane s

ą

do zadanego portu,

przydzielonego pewnej aplikacji.

Numery portów:

od 0 do 65535

.

Numery

zastrze

ż

one

portów:

od 0 do 1023

– zarezerwowane na usługi

takie, jak HTTP, FTP, itd.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 4

Klasy w

java.net

Komunikacj

ę

zgodn

ą

z tymi protokółami TCP i UDP realizuj

ą

klasy

pakietu

java.net

:



URL, URLConnection, Socket, ServerSocket

(dla TCP);



DatagramPacket, DatagramSocket, MulticastSocket

(dla UDP).

2) Klasa

URL

URL (Uniform Resource Locator) to adres zasobu w Internecie. URL
ma posta

ć

napisu specyfikuj

ą

cego:

protokół

dla dost

ę

pu do zasobu i

lokalizacj

ę

zasobu.

URL

jest te

ż

nazw

ą

klasy w

java.net

. Obiekt klasy

URL

reprezentuje

adres URL.

Konstruktory klasy

URL

1.

Z parametrem

typu

String

reprezentuj

ą

cym

adres bezwzgl

ę

dny.

Np.:

URL adresPW = new URL("http://www.pw.edu.pl/");

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 5

2.

Z dwoma parametrami

– obiektem URL reprezentuj

ą

cym adres

bazowy

i parametrem typu

String

reprezentuj

ą

cym

adres wzgl

ę

dny

.

Np.: dane s

ą

dwa adresy

URL

http://www.ia.pw.edu.pl/dydaktyka/proz.html
http://www.ia.pw.edu.pl/dydaktyka/probe.html

Mo

ż

na utworzy

ć

obiekty klasy URL dla obu stron na podstawie

adresów wzgl

ę

dem jednej bazy -

http://www.ia.pw.edu.pl/dydaktyka/

:

URL dydaktyka = new URL("http://www.ia.pw.edu.pl/dydaktyka/");
URL dydaktykaProz = new URL(dydaktyka, "proz.html");
URL dydaktykaProbe = new URL(dydaktyka, "probe.html");

korzystaj

ą

c z konstruktora:

URL(URL bazowyURL, String wzglednyURL)

Mo

ż

na te

ż

utworzy

ć

referencj

ę

do pozycji w dokumencie

. Np.

URL dydaktykaProzProjekt = new URL(dydaktykaProz, "#PROJEKT");

3. Trzy-argumentowy konstruktor URL:

new URL("http", "www.ia.pw.edu.pl", "/dydaktyka/proz.html");

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 6

4. Cztero-argumentowy konstruktor URL uwzgl

ę

dniaj

ą

cy numer portu.

Np.

URL dydaktykaProz = new URL("http", "www.ia.pw.edu.pl”,80,
"dydaktyka/proz.html");

utworzy obiekt klasy

URL

dla nast

ę

puj

ą

cego adresu URL:

http://www.ia.pw.edu.pl:80/dydaktyka/proz.html

Ka

ż

dy

z

kontruktorów

klasy

URL

mo

ż

e

zgłosi

ć

wyj

ą

tek

MalformedURLException

(gdy argumenty referuj

ą

null

lub nieznany

protokół).

try {
URL myURL = new URL(. . .)
} catch (MalformedURLException e) {

// obsługa wyjątku

. . .
}

Obiekty klasy URL

nie mog

ą

by

ć

zmieniane

po pierwszej inicjalizacji.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 7

Podstawowe metody klasy URL

Metody zwracaj

ą

ce pełny adres URL dla danego obiektu klasy

URL

:

String toString()
String toExternalForm().

Metody podaj

ą

ce informacje o stanie obiektu URL:

getProtocol

– podaje cz

ęść

URL dotycz

ą

c

ą

protokółu;

getHost

- podaje cz

ęść

URL dotycz

ą

c

ą

adresu hosta;

getPort

- podaje cz

ęść

URL dotycz

ą

c

ą

numeru portu (liczba integer lub

warto

ść

-1 gdy port nie jest ustawiony);

getFile

- podaje cz

ęść

URL dotycz

ą

c

ą

nazwy pliku;

getRef

- podaje cz

ęść

URL dotycz

ą

c

ą

referencji w pliku dokumentu.

Przykład 14.1

. Tworzenie i korzystanie z obiektu klasy

URL

.

import java.net.*;
import java.io.*;

public class ParseURL {

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 8

public static void main(String[] args) throws Exception {
URL aURL = new URL

("http://java.sun.com:80/docs/books/"

+ "tutorial/index.html#DOWNLOADING"

);

System.out.println("protocol = " + aURL.getProtocol());
System.out.println("host = " + aURL.getHost());
System.out.println("filename = " + aURL.getFile());
System.out.println("port = " + aURL.getPort());
System.out.println("ref = " + aURL.getRef());
}
}

Wynik pracy programu:

protocol = http
host = java.sun.com
filename = /docs/books/tutorial/index.html
port = 80
ref = DOWNLOADING

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 9

Metody klasy URL do poł

ą

cze

ń

w sieci

Metoda

openStream()

Metoda zwraca obiekt strumieniowy klasy

java.io.InputStream

zwi

ą

zany z adresem

URL

.

Przykład 14.2.

Wykorzystanie metody

openStream

()

do poł

ą

czenia w

sieci. Odczyt informacji - poprzez obiekt klasy

BufferedReader

i zapis na

standardowym wyj

ś

ciu.

import java.net.*;
import java.io.*;
public class
URLReader {
public static void main(String[] args) throws Exception {
URL yahoo = new URL("http://www.yahoo.com/");
BufferedReader in = new BufferedReader(

new InputStreamReader(

yahoo.openStream()));

String inputLine;

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 10

while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}

Metoda

openConnection()

Metoda zwraca obiekt klasy

URLConnection

, który mo

ż

e by

ć

wykorzystany do szczegółowej współpracy z adresem URL. Np.

try {

URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yahooConnection = yahoo.openConnection();

} catch (MalformedURLException e) {

//

new URL()

nie powiodło si

ę

. . .

}
catch (IOException e) {

//

openConnection()

nie powiodło si

ę

. . .
}

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 11

3) Metody klasy

URLConnection

Przykład 14.3.

Odczyt z URL

za pomoc

ą

obiektu klasy

URLConnection

.

import java.net.*;
import java.io.*;
public class
URLConnectionReader {
public static void main(String[] args) throws Exception {
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();

// Poł

ą

cz

BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));

// Pobierz strumie

ń

String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 12

Adresy URL do których doł

ą

czono

skrypty

cgi-bin

wymagaj

ą

, aby

zapisywa

ć

informacj

ę

do URL

.

Typowy przykład

zapisu do

URL

polega na wypełnieniu przez

u

ż

ytkownika zapytania podanego w postaci formatki na stronie HTML i

wysłaniu go do serwera pod adres URL. Przetwarza on zwykle skrypt

cgi-bin

po stronie serwera i odpowiada w postaci strony HTML.

Współpraca programu Javy ze skryptami cgi-bin po stronie serwera
wymaga mo

ż

liwo

ś

ci zapisu do

URL

przez ten program. Czyli wymaga

to realizacji nast

ę

puj

ą

cych kroków w rogramie:

1.

Utworzy

ć

obiekt typu

URL

.

2.

Otworzy

ć

poł

ą

czenie z tym

URL

.

3.

Ustawi

ć

mo

ż

liwo

ś

ci wyj

ś

ciowe dla

URLConnection

.

4.

Pobra

ć

strumie

ń

wyj

ś

ciowy z poł

ą

czenia – bedzie on

poł

ą

czony ze standardowym strumieniem wej

ś

ciowym

skryptu

cgi-bin

po stronie serwera.

5.

Zapisywa

ć

dane do strumienia wyj

ś

ciowego.

6.

Zamkn

ąć

strumie

ń

.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 13

Przykład 14.4.

Skrypt na naszej stronie sieci odczytuje napis ze

standardowego wej

ś

cia

, odwraca kolejno

ść

znaków napisu i zapisuje

wynik d

o standardowego wyj

ś

cia

. Skrypt wymaga danych wej

ś

ciowych

w formacie

string=napis,

gdzie napis jest napisem do odwrócenia.

import java.io.*;
import java.net.*;
public class
Reverse {
public static void main(String[] args) throws Exception {

if (args.length != 1) {

System.err.println("Wywołanie: java Reverse " + "napis");

System.exit(1);

}

String stringToReverse = URLEncoder.encode(args[0]);
URL url = new URL("http://java.sun.com/cgi-bin/backwards");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);

// Umożliwić wyjście do URL

PrintWriter out = new PrintWriter(
connection.getOutputStream());

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 14

out.println("string=" + stringToReverse);

out.close();

BufferedReader in = new BufferedReader(

new InputStreamReader(

connection.getInputStream()));

String inputLine;

while ((inputLine = in.readLine()) != null)

System.out.println(inputLine);

in.close();

}
}

Komentarz do programu:
1) Przetwarzanie parametrów programu z linii komend:

if (args.length != 1) {
System.err.println("Wywołanie: java Reverse " + "napis");
System.exit(-1);
}
String stringToReverse = URLEncoder.encode(args[0]);

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 15

Ma by

ć

tylko jeden parametr programu i kodowany on jest dla

przesłania (w tym spacje i znaki przestankowe) go do skryptu cgi-bin.

2) Utworzenie obiektu klasy URL dla skryptu na

java.sun.com

, otwarcie

URLConnection

i ustawienie poł

ą

czenia do zapisu:

URL url = new URL("http://java.sun.com/cgi-bin/backwards");
URLConnection c = url.openConnection();
c.setDoOutput(true);

// Ustawienie do zapisu

3) Utworzenie strumienia wyj

ś

ciowego

dla poł

ą

czenia i utworzenie na

nim obiektu

PrintWriter

:

PrintWriter out = new PrintWriter(c.getOutputStream());

Je

ś

li

URL

nie zezwala nam na zapis (brak wyj

ś

cia) to metoda

getOutputStream

zgłosi wyj

ą

tek

UnknownServiceException

.

4) Zapis danych do strumienia wyj

ś

ciowego i zamkni

ę

cie strumienia

:

out.println("string=" + stringToReverse);
out.close();

Strumien wyj

ś

ciowy klienta jest strumieniem wej

ś

ciowym serwera –

skryptu realizuj

ą

cego odrócenie kolejno

ś

ci liter.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 16

5) Odczytujemy informacj

ę

zwrotn

ą

ze skryptu

:

BufferReader in = new BufferedReader(
new InputStreamReader(c.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();

Przykład wyniku działania:

Reverse Me
reversed is:
eM esreveR

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 17

14.2 Mechanizm gniazdek TCP

Do

komunikacji

sieciowej

z

wykorzystaniem

protokółu

TCP

wykorzystywane s

ą

mechanizmy:



strumieni i



gniazdek (ang.

socket

) - udost

ę

pniany w pakiecie

java.net.*

.

Programista mo

ż

e skupi

ć

si

ę

na tym

jakie dane chce przesła

ć

i pod

jaki adres

albo

co chce odebra

ć

i sk

ą

d.

1) Gniazdka sieciowe dla

TCP: Socket i ServerSocket

Do

bezpo

ś

redniego komunikowania

u

ż

ywany jest obiekt klasy

Socket

,

a do

prowadzenia nasłuchu

-

ServerSocket

.

Tworz

ą

c gniazdko do komunikacji

typu

Socket

podajemy adres

komputera, z którym chcemy si

ę

poł

ą

czy

ć

oraz numer portu, na którym

ma zosta

ć

nawi

ą

zane poł

ą

czenie.

Np.:

Socket s = new Socket("localhost", 4444);

- gdy chcemy poł

ą

czy

ć

si

ę

z komputerem lokalnym na porcie 4444;

Socket s = new Socket("SOLARIS", 4444);

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 18

- gdy chcemy poł

ą

czy

ć

si

ę

z komputerem maj

ą

cym nazw

ę

SOLARIS

w

sieci lokalnej LAN na porcie 4444;

Socket s = new Socket("194.29.130.225", 4444);

- gdy chcemy poł

ą

czy

ć

si

ę

z komputerem o danym adresie IP na

porcie 4444;

Socket s = new Socket("www.ia.pw.edu.pl", 4444);

- gdy chcemy poł

ą

czy

ć

si

ę

z danym serwerem internetowym na porcie

4444.

Tworz

ą

c gniazdko do nasłuchu

typu

ServerSocket

, podajemy tylko

numer portu, na którym ma by

ć

prowadzony nasłuch, np.:

ServerSocket ss = new ServerSocket(4444);

Numer portu

musi zawiera

ć

si

ę

w przedziale

[0,...,65535]

. Jednak

ż

e

niektóre numery portów s

ą

zajmowane przez usługi sieciowe takie, jak

standardowe protokoły transmisji, np.: 21 przez FTP, 80 przez HTTP.
Ponadto pewnych portów u

ż

ywaj

ą

same systemy operacyjne.

W rezultacie u

ż

ywanie numerów portów z przedziału

[0,...,1023]

jest

zabronione.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 19

2) Realizacja prostej komunikacji

Przykład

14.5.a

.

Nawi

ą

zanie

komunikacji

pomi

ę

dzy

dwoma

programami. Najpierw przedstawiamy program serwera nasłuchuj

ą

cy

na gniazdku i odbieraj

ą

cy pojawiaj

ą

ce si

ę

dane.

//Serwer.java

import java.io.*;
import java.net.*;
public class
Serwer {

public static void main(String args[]) throws IOException {

ServerSocket ss = new ServerSocket(4444);

// Gniazdko nasłuchu

while(true) {

// Praca w p

ę

tli

Socket s = ss.accept();

// Oczekiwanie na poł

ą

czenie

DataInputStream dis = new DataInputStream(

s.getInputStream());

// Pobierz strumień

String msg = dis.readUTF();

// Odczyt danych ze strumienia

System.out.println(msg);

// Przetwarzaj dane – tu : wyprowadź

dis.close();

// Zamkni

ę

cie strumienia

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 20

s.close();

// Zamkni

ę

cie poł

ą

czenia – gniazdka

}

}

}

Powy

ż

szy program działa, jak praktycznie ka

ż

dy serwer,

w

niesko

ń

czonej p

ę

tli

.

Nasłuchuje

on na

porcie 4444

, korzystaj

ą

c z gniazdka

ServerSocket

.

Sam proces oczekiwania na poł

ą

czenie realizowany jest w metodzie

accept

.

Gdy na wybranym porcie pojawi si

ę

informacja o próbie uzyskania

poł

ą

czenia, nast

ę

puje

zako

ń

czenie nasłuchu

i

utworzenia

gniazdka

Socket

. Dalej nast

ę

puje

odczytanie strumienia podł

ą

czonego

do

gniazdka, zawarto

ść

jest wypisywana na ekran, a

strumie

ń

i gniazdo

s

ą

zamykane.

Nast

ę

pnie program serwera znowu czeka

na prób

ę

nawi

ą

zania

poł

ą

czenia. Proste u

ż

ycie p

ę

tli niesko

ń

czonej powoduje,

ż

e aby go

zako

ń

czy

ć

, musimy u

ż

y

ć

kombinacji klawiszy

Ctrl+C

.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 21

Przykład 14.5.b.

Wysłanie danych przez klienta. Program klienta

tworzy gniazdko

Socket

w celu nawi

ą

zania poł

ą

czenia z lokalnym

komputerem na porcie 4444. Po zaakceptowaniu poł

ą

czenia tworzony

jest strumie

ń

, przez który przesyłany jest obiekt typu

String

. Nast

ę

pnie

strumie

ń

i gniazdko s

ą

zamykane, a program ko

ń

czy działanie.

//Klient.java

import java.io.*;
import java.net.*;
public class
Klient {
public static void main(String args[]) throws IOException {
Socket s = new Socket("localhost", 4444);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF("Witaj w sieci!");

// Prze

ś

lij napis do serwera

dos.close();

// Zamknij strumie

ń

s.close();

// Zamknij gniazdko

}
}

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 22

Podsumowanie przykładu 14.5

Musimy najpierw skompilowa

ć

oba programy i uruchomi

ć

program

serwerowy. Nast

ę

pnie w drugim okienku-konsoli uruchamiamy

program kliencki. Ka

ż

de kolejne uruchomienie programu-klienta

spowoduje wy

ś

wietlenie jednego napisu w programie-serwerze, co

oznacza,

ż

e poł

ą

czenie jest skutecznie nawi

ą

zywane.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 23

14.3 Przykład aplikacji klient - serwer

Aplikacje sieciowe s

ą

tworzone w celu zdalnego wykonywania jakich

ś

konkretnych czynno

ś

ci b

ą

d

ź

udost

ę

pniania usług, czy zasobów.

Zobaczmy przykład aplikacji

klient-serwer

, która - poza

nawi

ą

zaniem

ł

ą

czno

ś

ci

- b

ę

dzie realizowała

zdaln

ą

obsług

ę

trzech polece

ń

systemowych:

list

- wy

ś

wietlenie zawarto

ś

ci bie

żą

cego katalogu na serwerze;

get

- pobranie pliku z serwera i wy

ś

wietlenie go na konsoli klienta;

exit

- zako

ń

czenie pracy klienta.

1) Program serwera
Przykład 14.6.

Program serwera pracuje w p

ę

tli niesko

ń

czonej

nasłuchuj

ą

c na

porcie 4444

i oczekuj

ą

c na

żą

dania poł

ą

cze

ń

od

klientów. Gdy takie nadchodz

ą

- ka

ż

demu przydzielany jest osobny

w

ą

tek do obsługi.

//PlikSerwer.java

import java.io.*;

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 24

import java.net.*;

/* W

ą

tek obsługuj

ą

cy poł

ą

czenie pracuje w p

ę

tli niesko

ń

czonej. Czyta

on ze strumienia podł

ą

czonego do gniazdka obiekt serializowalnej

klasy programisty

Command

, a dokładniej - najpierw czyta obiekt ze

strumienia, a nast

ę

pnie zmienia jego typ na

Command

. */

public class PlikSerwer implements Runnable {
Socket socket;
public PlikSerwer(Socket s) {
socket = s;
}
public void run() {

// Metoda dla w

ą

tku

try {
ObjectInputStream ois =
new ObjectInputStream(socket.getInputStream());

// Strumień wejściowy

ObjectOutputStream oos =

// i wyjściowy

new ObjectOutputStream(socket.getOutputStream());
while(true) {

// P

ę

tla niesko

ń

czona

Command cmd = (Command)ois.readObject();

// Odczyt obiektu

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 25

/* Nast

ę

pnie sprawdza zawarto

ść

odczytanego obiektu i w zale

ż

no

ś

ci

od niej tworzy odpowiedni obiekt klasy programisty

Response

.

Tworzonemu obiektowi przekazywany jest efekt obsługi polecenia, tzn.
napis na zako

ń

czenie pracy, lista plików w katalogu bie

żą

cym serwera,

czy zawarto

ść

konkretnego pliku. */

// Obsługa komendy zako

ń

czenia pracy klienta

if (cmd.getCommand() == Command.EXIT) {
send(oos, new Response(cmd, "Do zobaczenia"));
break;
}

// Obsługa wy

ś

wietlania zawarto

ś

ci bie

żą

cego katalogu serwera

else if (cmd.getCommand() == Command.LIST) {
File file = new File(".");

// Plik - aktualny katalog

send(oos, new Response(cmd, file.list()));

// Lista plików

}
else if (cmd.getCommand() == Command.GET) {

// Obsługa wy

ś

wietlenia zawarto

ś

ci danego pliku na serwerze

String filename = (String) cmd.getCommandArg();

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 26

File file = new File(filename);
byte buff [] = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(buff);

// Wczytaj dane z podanego pliku

fis.close();
send(oos, new Response(cmd, buff));

// Prze

ś

lij zawarto

ść

pliku

}
else { send(oos, new Response(cmd, "Nieznana komenda")); }
}
ois.close();

// Zamknij strumienie wej

ś

ciowy

oos.close();

// -“- wyj

ś

ciowy

socket.close();

// Zamknij gniazdko

}
catch(Exception e) {
System.out.println(e);
}
}

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 27

/* Obiekt zapisywany jest do strumienia wyj

ś

ciowego – czyli resultat

przesyłany jest do klienta w obiekcie klasy

Response

. */

private void send(ObjectOutputStream oos, Response response)
throws IOException {
oos.writeObject(response);
oos.flush();
}

/* Program serwera pracuje w p

ę

tli niesko

ń

czonej nasłuchuj

ą

c na

porcie 4444

i oczekuj

ą

c na

żą

dania poł

ą

cze

ń

od klientów. Gdy takie

nadchodz

ą

- ka

ż

demu przydzielany jest osobny w

ą

tek do obsługi. */

public static void main(String args[]) throws IOException {
ServerSocket ss = new ServerSocket(4444);

// Utwórz gniazdko

System.out.println("Nasłuchiwanie na porcie 4444...");
while(true) {
Socket s = ss.accept();

// Oczekuje na

żą

danie od klienta

System.out.println("Akceptuję połączenie z: "+s.getInetAddress());
(new Thread(new PlikSerwer(s))).start();

// Uruchom w

ą

tek obsługi

}

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 28

}
}

2) Klasy pomocnicze w tym przykładzie

Przykład 14.7

. Opiszemy tu klas

ę

pomocnicz

ą

serwera

Command.

Klasa pomocnicza zawiera deklaracje stałych identyfikuj

ą

cych

polecenia wydawane serwerowi przez klienta. Zawiera te

ż

zmienn

ą

okre

ś

laj

ą

c

ą

bie

żą

ce polecenie wydane serwerowi oraz metody j

ą

obsługuj

ą

ce. Cała klasa jest serializowana, aby jej obiekty mogły by

ć

zapisywane do strumieni.

//Command.java

import java.io.*;
public class
Command implements Serializable {
public final static int LIST = 0;
public final static int GET = 1;
public final static int EXIT = 2;
private int cmd;
private Object arg;
public Command (int cmd) {

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 29

this.cmd = cmd;
}
public Command (int cmd, Object arg) {
this.cmd = cmd;
this.arg = arg;
}
public int getCommand() {
return cmd;
}
public Object getCommandArg() {
return arg;
}
}

Przykład 14.8.

Opiszemy teraz klas

ę

Response

. Klasa zawiera prywatne

pole do przechowywania obiektu b

ę

d

ą

cego rezultatem realizacji

polecenia klienta. Dzi

ę

ki serializacji obiekty tej klasy mog

ą

by

ć

przesyłane za pomoc

ą

strumieni, tak samo jak obiekty

Command

.

// Response.java

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 30

import java.io.*;
public class
Response implements Serializable {
private Object data;
private Command cmd;
public Response (Command cmd, Object data) {
this.cmd = cmd;
this.data = data;
}
public Object getData() {
return data;
}
public Command getCommand() {
return cmd;
}
}

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 31

3) Program klienta w tym przykładzie

Przykład 14.9.

Program klienta.

// PlikKlient.java

import java.io.*;
import java.net.*;
public class
PlikKlient {
Socket socket;
ObjectOutputStream oos;
ObjectInputStream ois;
public PlikKlient(String host, int port) throws IOException {
socket = new Socket(host, port);
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
}
public void go() {
try {
BufferedReader br = new BufferedReader(

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 32

new InputStreamReader(System.in));

while(true) {
System.out.print("Zdalny>");
System.out.flush();
String line = br.readLine();

// Komenda końca pracy klienta

if (line.startsWith("exit")) {
Command cmd = new Command(Command.EXIT);
Response response = send(cmd);
System.out.println(response.getData());
System.exit(0);
}

//Komenda wyświetlenia zawartości bieżącego katalogu serwera

else if (line.startsWith("list")) {
Command cmd = new Command(Command.LIST);
Response response = send(cmd);
String list [] = (String []) response.getData();
for (int i=0; i<list.length; i++) {

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 33

System.out.println(list[i]);
}
}

//Komenda wyświetlenia zawartości danego pliku na serwerze

else if (line.startsWith("get")) {
Command cmd = new Command(Command.GET, line.substring(4));
Response response = send(cmd);
byte content [] = (byte []) response.getData();
System.out.println(new String(content));
}
else {
System.out.println("Nieznana komenda: "+line);
}
}
}
catch (Exception e) {
System.out.println(e);
}

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 34

}
private Response send(Command cmd) throws Exception {
oos.writeObject(cmd);
oos.flush();
return (Response) ois.readObject();
}
public static void main(String args[]) throws IOException {
(new PlikKlient("localhost", 4444)).go();
}
}

Program klienta odczytuje z konsoli polecenia od u

ż

ytkownika,

zapisuje je w postaci obiektów do strumienia podł

ą

czonego do

gniazdka pracuj

ą

cego na porcie 4444, odczytuje ze strumienia

przychodz

ą

ce z serwera odpowiedzi i wy

ś

wietla je na konsoli.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 35

4) Uruchomienie całej aplikacji

Po skompilowaniu wszystkich klas uruchamiamy serwer, a nast

ę

pnie

klienta (lub wielu klientów) - oczywi

ś

cie ka

ż

dy z programów

uruchamiany jest w osobnym okienku konsoli.

Gdy oba programy znajduj

ą

si

ę

na jednym komputerze (tj. testujemy

poł

ą

czenie na komputerze lokalnym), nie musz

ą

by

ć

umieszczone w

jednym katalogu. Jednak

ż

e wtedy zarówno w katalogu z serwerem -

jak i z klientem - musz

ą

znajdowa

ć

si

ę

skompilowane klasy

pomocnicze.

Po uruchomieniu obu programów mo

ż

emy wyda

ć

w konsoli klienta

które

ś

z trzech obsługiwanych polece

ń

i zobaczy

ć

efekt jego działania.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 36

14.4 RMI (Remote Method Invocation)

– model DOA

1) Model DOA

Mechanizm RMI wykorzystuje

model komunikacji klient-serwer

i

realizuje paradygmat programowania obiektowego - rozproszonego
(

DOA – distributed object application

):

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 37



program serwera

tworzy obiekty, udost

ę

pnia referencje do nich

(dzi

ę

ki ich zarejestrowaniu poprzez

rmiregistry

) i oczekuje na

wywołania metod na tych obiektach inicjowane przez klientów;



programy klientów

uzyskuj

ą

referencj

ę

do zdalnego obiektu i

wywołuj

ą

na nim metody.

2) Typowy schemat współpracy klient - serwer w RMI

(A) Zdalny interfejs i zdalny obiekt

Aplikacja z u

ż

yciem

Java RMI

składa si

ę

z interfejsów i klas, przy czym

spodziewamy si

ę

,

ż

e implementacje metod mog

ą

by

ć

rozproszone po

ż

nych maszynach.

Zdalnym obiektem

nazywamy obiekt, którego metody mog

ą

by

ć

wywoływane z ró

ż

nych maszyn wirtualnych Javy. Takie metody

deklarowane s

ą

w tzw.

zdalnych interfejsach

:



zdalny interfejs dziedziczy po interfejsie

java.rmi.Remote

,



w li

ś

cie wyj

ą

tków ka

ż

dej metody tego interfejsu istnieje deklaracja

wyj

ą

tku

java.rmi.RemoteException

.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 38

Serwer

zwi

ą

zuje nazw

ę

w rejestrze ze swoim

zdalnym obiektem,

który mo

ż

e by

ć

wołany zdalnie.

(B) Pobranie obiektu i wywołanie metody
Klient

odnajduje zdalny obiekt w

rejestrze

poprzez jego nazw

ę

i

wywołuje

na nim

metod

ę

interfejsu.


RMI nie kopiuje zdalnego obiektu do programu “odbiorcy” lecz
przekazuje “

namiastk

ę

” (stub)

zdalnego obiektu – reprezentuje ona

referencj

ę

do zdalnego obiektu. Ta referencja mo

ż

e by

ć

konwertowana

na dowolny

zdalny interfejs

implementowany przez klas

ę

zdalnego

obiektu. Klasa zdalnego obiektu pełni w programie klienta rol

ę

po

ś

rednika (proxy) w przekazie danych.

Zdalnie mo

ż

na wywoła

ć

wył

ą

cznie metody zdalnych interfejsów danej

klasy

.

(C) Dynamiczne ładowanie definicji klasy

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 39

Je

ś

li klasa obiektu

nie jest zdefiniowana

na maszynie “odbiorcy

obiektu” to RMI pobierze od „nadawcy” i prze

ś

le ten kod.

Mechanizm RMI korzysta z istniej

ą

cego

serwera sieciowego

dla

przekazywania

bajtkodu klas pomi

ę

dzy klientem a serwerem

– w obie

strony.

3) Podstawowe klasy i interfejsy w

java.rmi

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 40

4) Tworzenie aplikacji rozproszonej w

RMI

Nale

ż

y:



zdefiniowa

ć

komponenty aplikacji (lokalne i zdalne obiekty, zdalne

interfejsy, implementacje metod);



skompilowa

ć

program (kompilator

javac

) i wygenerowa

ć

„namiastki”

zdalnych obiektów (kompilator

rmic

);



udost

ę

pni

ć

klasy i namiastki obiektów w sieci,



uruchomi

ć

aplikacj

ę

(dokona

ć

rejestracji w rejestrze zdalnych

obiektów RMI, uruchomi

ć

serwer i klientów).

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 41

14.5

Przykład

aplikacji

rozproszonej

o

dynamicznie

ładowanym kodzie

Przykład 14.10.

Projekt

serwera oblicze

ń

w oparciu o mechanizm RMI

Serwer akceptuje zadania pochodz

ą

ce od klienta, wykonuje te zadania

i zwraca wyniki. Serwer składa sie ze zdalnego interfejsu

Compute

i

klasy

ComputeEngine

implementuj

ą

cej ten interfejs, przeznaczonej dla

utworzenia zdalnego obiektu. W metodzie

main

tej klasy nast

ę

puje

utworzenie tego obiektu, jego zarejestrowanie i ustawienie menad

ż

era

zabezpiecze

ń

(security manager).

Interfejsy typu “Remote Interface

W przykładzie wyst

ę

puj

ą

2 interfejsy zdalne deklaruj

ą

ce po jednej

metodzie.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 42

Interfejs

Compute

serwera

ComputeEngine

pozwala na dostarczanie

zadania do wykonania.

package compute;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Compute extends Remote {

Object executeTask(Task t) throws RemoteException;

}


Dziedziczenie z interfejsu

java.rmi.Remote

oznacza,

ż

e:



metody

dziedziczonego interfejsu mog

ą

by

ć

wołane z dowolnej

maszyny wirtualnej Javy;



obiekt z implementacj

ą

tego interfejsu staje si

ę

zdalnym obiektem

.


Zdalna

metoda

musi

deklarowa

ć

zgłaszanie

wyj

ą

tku

java.rmi.RemoteException

. Jest to

sprawdzalny wyj

ą

tek

.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 43

Interfejs klienta

Task

wyznacza sposób wykonania przez serwer

powierzonego zadania.

package compute;

import java.io.Serializable;

public interface Task extends Serializable {
Object execute();
}


Dziedziczenie interfejsu po

java.io.Serializable

oznacza,

ż

e obiekt klasy

implementuj

ą

cej ten interfejs mo

ż

e zosta

ć

zamieniony na strumie

ń

bajtów i jednoznacznie zrekonstruowany z niego.

Obiekty ró

ż

nych klas mog

ą

zosta

ć

przekazane do obiektu

Compute

,

je

ś

li tylko klasy implementuj

ą

interfejs

Task.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 44

Implementacja zdalnego interfejsu
Klasa u

ż

ytkownika

engine.ComputeEngine

implementuje interfejs zdalny

Compute

, a w jej metodzie

main

inicjalizowany jest obiekt tej klasy.

package engine;
import java.rmi.*;
import java.rmi.server.*;
import
compute.*;

public class ComputeEngine extends UnicastRemoteObject
implements Compute {

// Konstruktor –

public ComputeEngine() throws RemoteException {
super();

// Wywoła metod

ę

exportObject

// Konstruktor nadklasy został by wywołany – nawet przy braku

super();

}

// Metoda dla pobrania obiektu klienta do wykonania

public Object executeTask(Task t) {
return t.execute(); //

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 45

}

// Metoda

main

dla ustawienia obiektu

public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
String name = "//host/Compute";

// Okre

ś

la nazw

ę

obiektu

// zdalnego serwera

try {
Compute engine = new ComputeEngine();

// Utworzy obiekt

Naming.rebind(name, engine);

// Rejestracja obiektu zdalnego

System.out.println("Compute: związany");
} catch (Exception e) {

System.err.println("Compute: wyjątek " + e.getMessage());

e.printStackTrace();
}
}

// Koniec metody

main

!

}

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 46

Komentarz

1) Klasa serwera implementuje zdalny interfejs:

public class ComputeEngine extends UnicastRemoteObject
implements Compute

i dziedziczy po klasie bazowej

java.rmi.server.UnicastRemoteObject

.


Ta klasa zapewnia podstawow

ą

funkcjonalno

ść

zdalnego obiektu:



implementuje metody klasy

java.lang.Object

(

equals, hashCode

,

toString

) odpowiednio dla zdalnego obiektu;



zawiera konstruktory i metody statyczne przewidziane do

wyeksportowania zdalnego obiektu (

exportObject()

) tzn. aby zdalny

obiekt mógł odbiera

ć

wezwania od klientów;



zapewnia poł

ą

czenia „point-to-point” w oparciu o

gniazdka

.


Inna klasa dla zdalnych obiektów

java.rmi.activation.Activatable

(dla

zdalnych obiektów wywoływalnych na

żą

danie).

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 47

2) Konstruktor klasy

ComputeEngine

:

public ComputeEngine() throws RemoteException {
super();

// Nast

ę

puje tu te

ż

eksportowanie obiektu

}

Nale

ż

y zadeklarowa

ć

zgłaszalno

ść

w

ą

tku

RemoteException

, który

zostanie zgłoszony, gdy nie powiedzie si

ę

eksport obiektu.

3) Implementacje metod interfejsów zdalnych

Klasa implementuje jedn

ą

metod

ę

interfejsu zdalnego

Compute

metod

ę

executeTask

:

public Object executeTask(Task t) {
return t.execute();
}

Metoda wyznacza sposób komunikacji pomi

ę

dzy obiektem klasy

ComputeEngine

a jego klientami. Klienci przekazuj

ą

serwerowi obiekt

klasy implementuj

ą

cej interfejs

Task

i posiadaj

ą

cej implementacj

ę

metody

execute

.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 48

4) Klasa klienta

Do serwera mo

ż

e by

ć

przekazany obiekt dowolnego typu o ile jest to:

zmienna typu prostego, obiekt zdalny lub serializowalny obiekt (tzn.
jego klasa implementuje interfejs

java.io.Serializable

).

Sposoby przekazywania obiektów zdalnych, parametrów i wyników.
Zdalne obiekty

przekazywane s

ą

przez

referencj

ę

. Po stronie klienta

tworzona jest

namiastka obiektu

(stub) pełni

ą

ca rol

ę

proxy

(przekazuj

ą

c

ą

odwołania do rzeczywistego obiektu serwera).

Zwykłe obiekty

przekazywane s

ą

przez

warto

ść

poprzez ich

serializacj

ę

. W zdalnym wywołaniu metody – zwykłe obiekty

(parametry, zwracany wynik, wyj

ą

tki) s

ą

przekazywane przez

warto

ść

tworzona jest ich kopia w zdalnej wirtualnej maszynie Javy.

5) Metoda

main

Metoda

main()

klasy

ComputeEngine

nie jest elementem interfejsu, czyli

nie jest metod

ą

wywoływaln

ą

zdalnie.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 49

W pierwszej kolejno

ś

ci metoda

main()

powinna utworzy

ć

i zainstalowa

ć

zarz

ą

dc

ę

polityki bezpiecze

ń

stwa (

Security Manager

), w przeciwnym

razie mechanizm

RMI

nie zezwoli na ładowanie zdalnych klas.


W

RMI

dost

ę

pna jest klasa

RMISecurityManager

, która realizuje

pdobn

ą

polityk

ę

bezpiecze

ń

stwa, jak ta stosowana dla apletów.

if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}


Nast

ę

pnie

utworzony

zostaje

obiekt

klasy

ComputeEngine

i

udost

ę

pniony klientom na anonimowym porcie:

Compute engine = new ComputeEngine();

// Utworzenie obiektu


Mechanizm RMI zarz

ą

dza

rejestrem zdalnych obiektów

, z którego

mo

ż

na pobra

ć

referencj

ę

do zdalnego obiektu na podstawie jego

nazwy. Rejestr ten mo

ż

e by

ć

wspólny dla wszystkich serwerów na

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 50

danej maszynie albo te

ż

proces serwera mo

ż

e posiada

ć

odr

ę

bny taki

rejestr.

Metody dost

ę

pu do rejestru zdalnych obiektów wyznacza interfejs

java.rmi.Naming

(zwi

ą

zanie, rejestracja, pobranie).


W metodzie

main

klasy

ComputeEngine

nadajemy nazw

ę

String name = "//host/Compute";

//

host

to nazwa maszyny

//

Compute

to nazwa identyfikuj

ą

ca obiekt zdalny w rejestrze.

i rejestrujemy obiekt

engine

klasy

ComputeEngine

w rejestrze:

Naming.rebind(name, engine);


Podczas wywołania

rebind()

mo

ż

e powsta

ć

wyj

ą

tek:

RemoteException

.

Parametry wywołania metody

Naming.rebind

:

pierwszy parametr jest typu

java.lang.String

o postaci adresu

URL

;

Np.

//host:1234/objectname

Je

ś

li brak jest numeru portu to przyjmuje si

ę

domy

ś

lny port: 1099.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 51


Po zarejestrowaniu obiektu zdalnego i wydruku informacji o gotowo

ś

ci

do pracy metoda

main()

ko

ń

czy si

ę

wykonywa

ć

(

w

ą

tek główny ko

ń

czy

swoje wykonanie !).
Jednak

istnieje referencja

do obiektu przekazana innemu obiektowi –

bed

ą

cemu rejestrem zdalnych obiektów.

Mechanizm RMI pilnuje, aby proces dla obiektu

ComputeEngine

nadal

istniał.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 52

Przykład 14.11

Program klienta musi definiowa

ć

zadanie, które ma

wykona

ć

w jego imieniu serwer. W tym przykładzie klient składa si

ę

z 2

klas:

ComputePi

– w celu pobrania obiektu serwera

Compute

;

Pi

-

klasa implementuj

ą

ca interfejs

Task

i definiuj

ą

ca zadanie.

Definicja

Task

:

package compute;
public interface Task extends java.io.Serializable {
Object execute();
}


Klasa klienta

client.ComputePi

package client;

import java.rmi.*;
import java.math.*;
import
compute.*;

public class ComputePi {

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 53

public static void main(String args[]) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {

// Nazwa serwera w formacie URL

String name = "//" + args[0] + "/Compute";

// Pobierz referencje do obiektu zdalnego serwera:

Compute comp = (Compute) Naming.lookup(name);
Pi task = new Pi(Integer.parseInt(args[1]));

// Wywołaj metod

ę

executeTask

obiektu zdalnego

comp

// przekazuj

ą

c zadanie do wykonania

task

:

BigDecimal pi = (BigDecimal) (comp.executeTask(task));
System.out.println(pi);

// Wydrukuj obliczony wynik

} catch (Exception e) {
System.err.println("ComputePi exception: " +
e.getMessage());
e.printStackTrace();

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 54

}
}
}


Przepływ informacji pomi

ę

dzy obiektem klienta klasy

ComputePi

,

rejestrem obiektów zdalnych

rmiregistry

i obiektem serwera

ComputeEngine

.

Komentarz
1) Klasa klienta instaluje menad

ż

era bezpiecze

ń

stwa

Jest to niezb

ę

dne, gdy

ż

RMI mo

ż

e ładowa

ć

kod do procesu klienta – w

tym przypadku namiastk

ę

obiektu

ComputeEngine

.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 55

Podobnie jak serwer równie

ż

klient korzysta tu z menad

ż

era

bezpiecze

ń

stwa dost

ę

pnego w systemie RMI.

2) Klient tworzy nazw

ę

do nadzoru obiektu zdalnego typu

Compute

Pierwszy parametr z linii wywołania programu,

args[0]

, stanowi nazw

ę

zdalnej maszyny, na której wykonuje si

ę

object typu

Compute

.

Klient odwołuje si

ę

do metody

Naming.lookup

w celu odszukania

obiektu po jego nazwie w rejestrze zdalnych obiektów zdalnego hosta.
Parametr metody (typu

String

) ma t

ę

sam

ą

składni

ę

adresu URL jak

parametr metody

Naming.rebind

w przypadku rejestracji obiektu przez

serwer.

3) Klient tworzy nowy obiekt klasy

Pi

Argumentem wywołania konstruktora

Pi

jest drugi paramer z inii

wywołania programu klienta,

args[1]

, podaj

ą

cy liczb

ę

pozycji

dziesi

ę

tnych dla oblicze

ń

.

4) Klient wywołuje metod

ę

executeTask

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 56

Klient wywołuje metod

ę

executeTask

zdalnego obiektu typu

Compute

.


Defnicja klasy

client.Pi

, która implementuje inerfejs

Task

:

package client;
import compute.*;
import java.math.*;
public class Pi
implements Task {

/** Stałe potrzebne dla obliczenia watości pi */

private static final BigDecimal ZERO = BigDecimal.valueOf(0);
private static final BigDecimal ONE = BigDecimal.valueOf(1);
private static final BigDecimal FOUR = BigDecimal.valueOf(4);

/** Tryb zaokrąglania */

private static final int roundingMode = BigDecimal.ROUND_HALF_EVEN;

/** Precyzja - liczba pozycji po kropce dziesiętnej */

private int digits;

/** Konstruktor */

public Pi(int digits) {

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 57

this.digits = digits;
}

/** Oblicz pi */

public Object execute() {
return computePi(digits);
}

/** według formuły
* pi/4 = 4*arctan(1/5) - arctan(1/239)
* i po rozwinięciu arctan(x) w szereg.
*/

public static BigDecimal computePi(int digits) {
int scale = digits + 5;
BigDecimal arctan1_5 = arctan(5, scale);
BigDecimal arctan1_239 = arctan(239, scale);
BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
arctan1_239).multiply(FOUR);
return pi.setScale(digits,

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 58

BigDecimal.ROUND_HALF_UP);
}

/**
* Oblicza wartość arct tangens w radianach według wzoru:
* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + (x^9)/9 ...
*/

public static BigDecimal arctan(int inverseX, int scale)
{
BigDecimal result, numer, term;
BigDecimal invX = BigDecimal.valueOf(inverseX);
BigDecimal invX2 =
BigDecimal.valueOf(inverseX * inverseX);

numer = ONE.divide(invX, scale, roundingMode);
result = numer;
int i = 1;
do {
numer =
numer.divide(invX2, scale, roundingMode);

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 59

int denom = 2 * i + 1;
term =
numer.divide(BigDecimal.valueOf(denom),
scale, roundingMode);
if ((i % 2) != 0) { result = result.subtract(term);
} else { result = result.add(term);
}
i++;
} while (term.compareTo(ZERO) != 0);
return result;
}

}

Uwaga

Obiekt klasy

Compute

nie wymaga definicji klasy

Pi

dopóki obiekt klasy

Pi

nie zostanie przekazany jako argument metody

executeTask

. W tym

momencie kod klasy ładowany jest przez RMI do maszyny wirtualnej
wła

ś

ciwej dla obiektu typu

Compute

, wołana jest metoda

execute

klasy

Pi

i wykonuje si

ę

kod tej metody. Wynikowy obiekt typu

Object

, w tym

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 60

przypadku jest on typu

java.math.BigDecimal

, jest przekazywany

zwrotnie do klienta, w którym nast

ę

puje wydruk tego obiektu.


Z punktu widzenia serwera – obiektu typu

ComputeEngine

– jest bez

znaczenia, co oblicza zlecona metoda. Jedyne co musi wiedzie

ć

obiekt

klasy implementuj

ą

cej

Compute

o przekazywanym obiekcie to to,

ż

e

jego klasa posiada metod

ę

execute

.

Dynamiczne ładowanie klas


Poni

ż

szy rysunek ilustruje sk

ą

d ładowane s

ą

definicje klas potrzebnych

programom:

rmiregistry

, serwerowi

ComputeEngine

, i klientowi

ComputePi

podczas wykonania rozproszonej aplikacji Javy.

Gdy serwer

ComputeEngine

rejestruje (bind) swój zdalny obiekt w

rejestrze, rejestr pobiera klas

ę

ComputeEngine_Stub

i interfejsy

Compute

i

Task

, od której ta klasa zale

ż

y. Te klasy pobierane s

ą

z

serwera sieciowego wła

ś

ciwego dla

ComputeEngine

lub z systemu

plików.

background image

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 61

Klient typu

ComputePi

ładuje klas

ę

ComputeEngine_Stub

z serwera

sieci wła

ś

ciwego dla

ComputeEngine

w wyniku wykonania metody

Naming.lookup

. Klient

ComputePi

dysponuje opisami interfejsów

Compute

i

Task

, dlatego te

ż

ładowane s

ą

one z jego lokalnego

katalogu klas.

Na koniec, do maszyny wirtualnej wykonuj

ą

cej serwer

ComputeEngine

ładowany jest kod klasy

Pi

, gdy obiekt klasy

Pi

przekazywany jest w

zdalnym wywołaniu metody

executeTask

na rzecz obiektu typu

ComputeEngine

– klasa

Pi

ładowana jest z serwera sieciowego

wła

ś

ciwego dla klienta.

14. Komunikacja rozproszona

W. Kasprzak: Programowanie zdarzeniowe

14 - 62

Kompilacja i uruchomienie aplikacji

(serwera i klientów) oraz obliczenie

warto

ś

ci

π

.

1) Tworzymy pliki typu JAR (Java ARchive) zawieraj

ą

cy interfejsy

Compute

i

Task

dla implementacji ich przez klasy serwera i z

których korzysta program klienta.

2) Tworzymy implementacj

ę

interfejsu

Compute

i instalujemy t

ę

usług

ę

na maszynie udost

ę

pniaj

ą

c j

ą

klientom.

3) Twórcy programów klientów, korzystaj

ą

c z interfejsów

Compute

i

Task

, zawartych w pliku JAR, mog

ą

niezale

ż

nie od siebie utworzy

ć

zadanie (

Task

) i program klienta korzystaj

ą

cego z usługi

Compute

.

Klasa klienta

Pi

ładowana jest na serwer podczas wykonania.

Podobnie zdalna namiastka dla

ComputeEngine

ładowana jest z

serwera na maszynie klienta podczas wykonania.
Mamy trzy pakiety:

compute ( interfejsy

Compute

i

Task

)

engine (klasa implementuj

ą

ca

ComputeEngine

i jej namiastka)

client (kod klienta

ComputePi

i implementacja zadania

Pi

).


Wyszukiwarka

Podobne podstrony:
Proz S2 id 402992 Nieznany
Proz S12 id 402989 Nieznany
Proz S9 id 402999 Nieznany
Proz S8 id 402998 Nieznany
Proz S13 id 402990 Nieznany
Proz S4 id 402994 Nieznany
Proz S3 id 402993 Nieznany
Proz S7 id 402997 Nieznany
Proz S10 id 402987 Nieznany
Proz S5 id 402995 Nieznany
Proz S2 id 402992 Nieznany
Proz S12 id 402989 Nieznany
chemia proz maj 2011 cke id 112 Nieznany
Abolicja podatkowa id 50334 Nieznany (2)
4 LIDER MENEDZER id 37733 Nieznany (2)
katechezy MB id 233498 Nieznany
metro sciaga id 296943 Nieznany
perf id 354744 Nieznany
interbase id 92028 Nieznany

więcej podobnych podstron