Studium podyplomowe Sieci komputerowe

Konfiguracja PVM

1. Dodanie w pliku ~/.rhosts nazw komputerów w celu umożliwienia zdalnego logowania bez podawania hasła. Postać pliku:

  nazwa_hosta       nazwa_użytkownika
  inna_nazwa_hosta  nazwa_użytkownika
  ...
  

Nazwa użytkownika może być pominięta, jeżeli na komputerze zdalnym i lokalnym ta nazwa jest taka sama

2. Przetestowanie działania rsh:

rsh nazwa_zdalnego_hosta

W rezultacie wykonania polecenia powinniśmy zalogować się na wskazany komputer bez podawania hasła

3. Ustawienie zmiennych środowiskowych: W pliku ~/.bashrc dopisujemy:

                                                                                                                                             
export PVM_ROOT=/usr/lib/pvm3                                                                                                                  
export PVM_ARCH=`$PVM_ROOT/lib/pvmgetarch`                                                                                                     
export PVM_HOME=$HOME/pvm3/bin/$PVM_ARCH/                                                                                                      

4. Stworzenie katalogu na pliki wykonywalne:

mkdir -p $PVM_HOME                                                                                                                             
                                                                                                                                             

5. Przygotowanie pliku konfiguracyjnego dla PVM. Przykładowa postać pliku:

                                                                                                                                             
lab-sec-1                                                                                                                                      
lab-sec-2                                                                                                                                      
lab-sec-3                                                                                                                                      
                                                                                                                                             

6. Uruchomienie pvm:

pvm nazwa_pliku_konfiguracyjnego                                                                                                               
                                                                                                                                             

7. Odczytanie informacji o dostępnych hostach poleceniem conf

8. Dodanie nowego hosta poleceniem:

add nazwa_hosta  

9. Usunięcie jednego z hostów poleceniem:

delete nazwa_hosta                                                                                                                             
                                                                                                                                             

Zadanie

Napisać aplikację równlogłą do wyznaczania przybliżonej wartości liczby π metodą Monte Carlo. Realizację można oprzeć na poniżej wersji sekewncyjnej:

#include <stdio.h>
#include <stdlib.h>
 
main(){
   unsigned long n = 0, N = 0, i;
   double x, y;
 
   for( i = 0; i < 100000; i++ ){
      x = drand48();
      y = drand48();
      N++;
      if ( x*x + y*y <= 1 )
         n++;
   } // for
   printf( "%lf\n", 4.0*n/N );
}

1. Zrealizować aplikację zgodnie ze schematem master-slave: master uruchamia procesy slave, które odsyłają do niego wyniki obliczeń.

Program mastera

#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>
 
#define MAX_SLAVE 5
 
   main() {
      int tids[MAX_SLAVE];
      int num_tids;
      unsigned long n, N, suma_n = 0, suma_N = 0;
 
      num_tids = pvm_spawn("pi_slave", NULL, PvmTaskDefault, "", MAX_SLAVE, tids);
      if (num_tids <= 0){
         fprintf(stderr, "Blad uruchomienia slave'ow\n");
         pvm_exit();
         exit(1);
      }
      for(;;){
         pvm_recv(-1, -1);
         pvm_upkulong(&n, 1, 1);
         suma_n += n;
         pvm_upkulong(&N, 1, 1);
         suma_N += N;
         printf( "%lf\n", 4.0*n/N );
      }
   }

Program slave'a

#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>
 
   main(){
      unsigned long n = 0, N = 0, i;
      double x, y;
      int master_tid, my_tid;
 
   	  my_tid = pvm_mytid();
   	  srand48(my_tid);
      master_tid = pvm_parent();
      for(;;){
         for( i = 0; i < 100000; i++ ){
            x = drand48();
            y = drand48();
            N++;
            if ( x*x + y*y <= 1 )
               n++;
         } // for
         //printf( "%lf\n", 4.0*n/N );
         pvm_initsend(PvmDataRaw);
         pvm_pkulong(&n, 1, 1);
         pvm_pkulong(&N, 1, 1);
         pvm_send(master_tid, 1);
      }
   }

2. Zastosować mechanizm dynamicznych grup procesów w celu udostępnienia możliwości dodawania nowych zadań w trakcie obliczeń.

Program mastera

#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>
 
#define MAX_SLAVE 5
 
   main() {
      int tids[MAX_SLAVE];
      int num_tids;
      unsigned long n, N, suma_n = 0, suma_N = 0;
 
      pvm_mytid();
      pvm_joingroup("pi");
      /*
      num_tids = pvm_spawn("pi_slave", NULL, PvmTaskDefault, "", MAX_SLAVE, tids);
      if (num_tids <= 0){
         fprintf(stderr, "Blad uruchomienia slave'ow\n");
         pvm_exit();
         exit(1);
      }
      */
      for(;;){
         pvm_recv(-1, -1);
         pvm_upkulong(&n, 1, 1);
         suma_n += n;
         pvm_upkulong(&N, 1, 1);
         suma_N += N;
         printf( "%lf\n", 4.0*n/N );
      }
   }

Program slave'a

#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>
 
   main(){
      unsigned long n = 0, N = 0, i;
      double x, y;
      int master_tid, my_tid;
 
      my_tid = pvm_mytid();
   	  srand48(my_tid);
      //master_tid = pvm_parent();
      master_tid = pvm_gettid("pi", 0);
      for(;;){
         for( i = 0; i < 100000; i++ ){
            x = drand48();
            y = drand48();
            N++;
            if ( x*x + y*y <= 1 )
               n++;
         } // for
         //printf( "%lf\n", 4.0*n/N );
         pvm_initsend(PvmDataRaw);
         pvm_pkulong(&n, 1, 1);
         pvm_pkulong(&N, 1, 1);
         pvm_send(master_tid, 1);
      }
   }

Sposób kompilacji

cc pi_master.c -o pi_master -L$PVM_ROOT/lib/LINUX64 -lpvm3 -lgpvm3
cc pi_slave.c  -o pi_slave  -L$PVM_ROOT/lib/LINUX64 -lpvm3 -lgpvm3

3. Zmodyfikować aplikację w taki sposób, żeby obliczenia rozpoczynały się dopiero po uzyskaniu gotowości do działania przez co najmniej 4 procesy typu slave.

Oprogramowanie middleware

Slajdy do wykładów

Zagadnienia laboratoryjne

Narzędzia przetwarzania rozproszonego

Slajdy do wykładów

  1. Message Passing Interface (MPI) Tutorial Williama Groppa (1 slajd/stronę)
  2. Wywoływanie zdalnych procedur (RPC) 2 slajdy/stronę, 3 slajdy/stronę, 4 slajdy/stronę, 6 slajdów/stronę
  3. Współbieżność w środowisku Java 2 slajdy/stronę, 3 slajdy/stronę, 4 slajdy/stronę, 6 slajdów/stronę
  4. Wywoływanie zdalnych metod
  5. Ada

Zadania z synchronizacji

Środowiska przetwarzania rozproszonego (SUM SK)

Slajdy do wykładów

do uzupłenienia

Zagadnienia laboratoryjne

PVM (05.11.2016)

Przykładowy program korzystający z PVM: example.tar.gz

Konfiguracja PVM

1. Dodanie w pliku ~/.rhosts nazw komputerów w celu umożliwienia zdalnego logowania bez podawania hasła. Postać pliku:

  nazwa_hosta       nazwa_użytkownika
  inna_nazwa_hosta  nazwa_użytkownika
  ...
  

Nazwa użytkownika może być pominięta, jeżeli na komputerze zdalnym i lokalnym ta nazwa jest taka sama

2. Przetestowanie działania rsh:

rsh nazwa_zdalnego_hosta

W rezultacie wykonania polecenia powinniśmy zalogować się na wskazany komputer bez podawania hasła

3. Ustawienie zmiennych środowiskowych: W pliku ~/.bashrc dopisujemy:

                                                                                                                                             
export PVM_ROOT=/usr/lib/pvm3                                                                                                                  
export PVM_ARCH=`$PVM_ROOT/lib/pvmgetarch`                                                                                                     
export PVM_HOME=$HOME/pvm3/bin/$PVM_ARCH/                                                                                                      

4. Stworzenie katalogu na pliki wykonywalne:

mkdir -p $PVM_HOME                                                                                                                             
                                                                                                                                             

5. Przygotowanie pliku konfiguracyjnego dla PVM. Przykładowa postać pliku:

                                                                                                                                             
lab-sec-1                                                                                                                                      
lab-sec-2                                                                                                                                      
lab-sec-3                                                                                                                                      
                                                                                                                                             

6. Pobranie i rozpakowanie pliku example.tar.gz

7. Zbudowanie programu master i salve poleceniem make

8. Uruchomienie pvm:

pvm nazwa_pliku_konfiguracyjnego                                                                                                               
                                                                                                                                             

9. Odczytanie informacji o dostępnych hostach poleceniem conf

10. Dodanie nowego hosta poleceniem:

add nazwa_hosta  

11. Usunięcie jednego z hostów poleceniem:

delete nazwa_hosta                                                                                                                             
                                                                                                                                             

12. Uruchomienie przykładowego programu:

spawn -> master  
Zadanie

Napisać aplikację równlogłą do wyznaczania przybliżonej wartości liczby π metodą Monte Carlo. Realizację można oprzeć na poniżej wersji sekewncyjnej:

#include <stdio.h>
#include <stdlib.h>
 
main(){
   unsigned long n = 0, N = 0, i;
   double x, y;
 
   for( i = 0; i < 100000; i++ ){
      x = drand48();
      y = drand48();
      N++;
      if ( x*x + y*y <= 1 )
         n++;
   } // for
   printf( "%lf\n", 4.0*n/N );
}
  1. Zrealizować aplikację zgodnie ze schematem master-slave: master uruchamia procesy slave, które odsyłają do niego wyniki obliczeń. pi.tar.gz
  2. Zastosować mechanizm dynamicznych grup procesów w celu udostępnienia możliwości dodawania nowych zadań w trakcie obliczeń. reduce.tar.gz
  3. Zmodyfikować aplikację w taki sposób, żeby obliczenia rozpoczynały się dopiero po uzyskaniu gotowości do działania przez co najmniej 4 procesy typu slave.

RPC

Prosta aplikacja klienta dla rusers

1. Pobranie implementacji serwera:

rtime.tar

2. Skompilowanie i uruchomienie serwera.

3. Sprawdzenie listy zarejestrowanych programów RPC:

/usr/sbin/rpcinfo -p

4. Implementacja klienta pobierającego aktualny czas (po stronie serwera). Wykorzystanie funkcji:

int callrpc(char *host, unsigned long prognum,
                 unsigned long versnum, unsigned long procnum,
                 xdrproc_t inproc, char *in,
                 xdrproc_t outproc, char *out);

zadeklarowanej w pliku nagłówkowym:

rpc/rpc.h

Numery programu i procedury pobrać można z pliku nagłówkowego:

rtime.h

gdzie zdefiniowane są stałe:

TIMEPROG
TIMEVER_1 
get_time

Procedura get_time nie wymaga parametrów wejściowych (xdr_void), a jako wynik (parametr out) zwraca zmienną int (xdr_int) oznaczającą liczbę zalogowanych użytkowników.

5. Kompilacja programu klienta:

gcc -o rtime_client rtime_client.c
Usługa zdalnego zabijania procesów

Zadanie: napisać aplikację (serwer+klient) umożliwiającą zdalne zabijanie procesów. Klient ma uruchamiać zdalną procedurę, która jako parametr przyjmuje PID procesu do zabicia. Procedura zdalna jako wynik zwraca int określający status zakończenia operacji (0 - proces został unicestwiony, -1 - wystąpił błąd)

1. Utworzenie pliku rkill.x z opisem usługi:

program RKILL_PROG {
  version RKILL_VERS_1 {
    int rkill(int pid) = 1;
  } = 1;
} = 0x22000000;

2. Wygenerowanie części kodu programem:

rpcgen -a -N rkill.x

Program wygeneruje następujące pliki:

rkill.h          - plik nagłówkowy z definicjami stałych
rkill_client.c   - szkielet aplikacji klienta
rkill_server.c   - szkielet aplikacji serwera
rkill_clnt.c     - stub klienta
rkill_svc.c      - stub serwera
Makefile.rkill

3. Kompilacja z wykorzystaniem Makefile:

make -f Makefile.rkill

4. Implementajca zabijania procesu w pliku rkill_server.c z wykorzystaniem funkcji:

int kill(pid_t pid, int sig)  (man 2 kill)

5. Dodanie wyświetlania statusu wykonania po stronie klienta (plik rkill_clietn.c)

6. Dodanie drugiego argumentu dla zdalnej procedury: numer wysyłanego sygnału

a) zmiana definicji w pliku rkill.x:

int rkill(int pid, int signum) = 1;

b) ponowne wygenerowanie kodu programem rpcgen

c) implementajca funkcjonalności serwera i klienta

7. Dodanie procedury echo, która pozwala na wypisanie po stronie serwera tekstu przesłanego przez klienta

8. Przetestowanie działania mechanizmu timeout poprzez:

a) zabicie serwera

b) opóźnienie wysłania odpowiedzi przez serwer przy użyciu funkcji:

unsigned int sleep(unsigned int seconds);

test dla komunikacji po udp oraz po tcp

9. Ustawianie timeout dla klienta:

a) modyfikacja stałej:

TIMEOUT

zdefiniowanej w pliku:

rkill_clnt.c

b) wykorzystanie funkcji:

bool_t clnt_control(CLIENT *cl, int req, char *info);
req = CLSET_TIMEOUT - ustawianie wartości timeout
req = CLSET_RETRY_TIMEOUT - ustawianie czasu dla ponawiania żądania (tylko UDP)

Przykład:

struct timeval tm = { 60, 0 };
clnt = clnt_create (host, RKILL_PROG, RKILL_VERS_1, "udp");
clnt_control(clnt, CLSET_TIMEOUT, &tm);
Wywołanie asynchroniczne

Zadanie: Zmodyfikować rkill tak, aby klient mógł kontynuować przetwarzanie bez oczekiwania na zakończenie obliczeń przez serwer (zakładamy, że klienta nie interesuje odpowiedź od serwera)

RMI

HelloWorld

1. Utworzyć plik z interfejsem programu HelloWorld

import java.rmi.Remote;
import java.rmi.RemoteException;
                                
public interface HelloWorld extends Remote {
      String getString(String name) throws RemoteException;
}

2. Napisać aplikację klienta odwołującego się do zdalnego obiektu implementującego interfejs HelloWorld:

a) rejestr, w którym zarejestrowany został zdalny obiekt znajduje się pod adresem wskazanym przez prowadzącego

b) program klienta pobiera z rejestru referencję na zdalny obiekt korzystając z metody Naming.lookup(String name);

c) program klienta wywołuje zdalną metodę getString jako argument podając tekst pobrany z linii komend przy uruchamianiu programu

d) napis zwrócony przez metodę getString należy wypisać na standardowe wyjście

e) skompilować program klienta

javac *.java

f) utworzyć plik client.policy z definicją polityk bezpieczeństwa:

grant {
  permission java.security.AllPermission;
};

g) uruchomić program klienta

java -Djava.security.policy=client.policy HelloWorldClient

3. Napisać własną implementację serwera HelloWorld:

a) przygotować klasę HelloWorldObj rozszerzający klasę UnicastRemoteObject oraz implementujący interfejs HelloWorld

b) przygotować klasę HelloWorldServer, która w metodzie main utworzy instancję klasy HelloWorldObj, a następnie zarejestruje ten obiekt w rejestrze przy użyciu metody:

Naming.rebind("//127.0.0.1:2100/HelloWorld")

c) skompilować program

d) uruchomić rejestr RMI

rmiregistry nr_portu

e) uruchomić i przetestować serwer

java -Djava.rmi.server.hostname=127.0.0.1 -Djava.security.policy=server.policy HelloWorldServer

4. Przerobić program serwera tak, aby uruchamiał swój własny rejestr

Registry registry = LocateRegistry.createRegistry(2100);
registry.rebind("HelloWorld", obj);
Przekazywanie obiektów przez wartość i przez referencję

1. Zaimplementować klasę ArgumentObject zawierającą prywatne pole value typu int oraz metody umożliwiające odczyt i nadpisanie wartości tego pola. Klasa powinna implementować interfejs java.io.Serializable

2. Umieścić implementację ArgumentObject w classpath klienta i serwera

3. Przerobić implementację HelloWorldObj, tak aby metoda getString przyjmowała jako argument obiekt klasy ArgumentObject, odczytywała wartość zdefiniowanego w tej klasie pola, nadpisywała wartość tego pola i zwracała odczytaną wcześniej wartość w postaci obiektu typu String.

4. Przerobić program klienta, tak aby tworzył obiekt ArgumentObject i podawał go jako argument wywołania metody getString ze zdalnego obiektu HelloWorldObj; następnie klient powinien wypisać odczytany String oraz aktualną wartość pola value z klasy ArgumentObject

5. Sprawdzić rezultat działania programu

6. Przerobić program, tak aby ArgumentObject przekazywany był przez referencję; w tym celu należy:

a) zdefiniować interfejs Argument rozszerzający interfejs Remote i umieścić go w classpath serwera i klienta,

b) przerobić implementację ArguentObject, tak aby rozszerzał UnicastRemoteObjet oraz implementował interfejs Argument,

c) usunąć klasę ArgumentObject z classpath serwera

7. Uruchomić program i zaobserwować zmiany w działaniu

RemoteComputation

Zadanie: przygotować program umożliwiający wykonywanie po stronie serwera dowolnych obliczeń zleconych przez klienta:

1. Serwera udostępnia zdalny obiekt implementujący interfejs Compute

public interface Compute {
  Object runTask(Task task, Args args);
}

2. Task jest interfejsem reprezentującym zadanie obliczeniowe, posiada metodę run(Args args), która jest wywoływana wewnątrz metody runTask

3. Klient dostarcza co najmniej dwie implementacje interfejsu Task, np. wykonujące dodawanie i mnożenie; obie klasy muszą implementować interfejs Serializable

4. Klient korzystając z rejestru pobiera referencję na zdalny obiekt Compute i wywołuje metodę runTask podając jako argument jedną z implementacji interfejsu Task; wynik zwrócony przez runTask jest wypisywany na standardowe wyjście

5. Klient dostarcza serwerowi klasy z implementacją Task poprzez http lub system plików, przykładowe wywołanie programu klienta wygląda wówczas następująco:

java -Djava.rmi.server.codebase=file:///path/to/Task/implementation/ -Djava.security.policy=client.policy ComputeClient
Accounts

Zadanie: zaimplementować program do zdalnego wykonywania operacji na kontach bankowych

1. Serwer udostępnia zdalny obiekt umożliwiający pobranie listy kont bankowych

public interface AccountList extends Remote {
      List<Account> getList() throws RemoteException;
}

2. Interfejs Account rozszerza interfejs Remote i umożliwia przeprowadzenie podstawowych operacji na koncie

public interface Account extends Remote {                                                                                                                                         
      public Integer getBalance() throws RemoteException; //pobranie stanu konta
      public Integer add(Integer amount) throws RemoteException; //dodanie określonej kwoty do stanu konta
      public Integer withdraw(Integer amount) throws RemoteException; //pobranie określonej kwoty z konta
}

3. Klient korzystając ze zdalnego obiektu implementującego AccountList pobiera listę zdalnych referencji na obiekty typu Account

4. Do wybranego konta klient dopisuje określoną kwotę i sprawdza aktualny stan tego konta

5. Sprawdzenie, czy modyfikacja stanu konta zapamiętywana jest między kolejnymi uruchomieniami programu klienta

Rozwiązania

JMS

1. Pobierz ze strony mq.java.net

Open MQ 4.5 (zip archive, no installer)

2. Uruchom program brokera:

bin/imqbrokerd

3. Zaimplementuj:

a) program HelloProvider wysyłający wiadomość tekstową do kolejki (Queue)

b) program HelloConsumer pobierający synchronicznie wiadomość z kolejki i wypisujący jej treść na ekranie

4. W aplikacji z punktu 3. zmień Queue na Topic i porównaj sposób działania.

5. Zaimplementuj program konsumenta, który odbiera wiadomości z kolejki asynchronicznie.

6. Zaimplementuj konsumenta korzystającego z mechanizmu trwałej subskrypcji.

7. Przetestuj mechanizm filtrowania wiadomości.

start.txt · ostatnio zmienione: 2017/01/13 22:02 przez sfrancuzik
 
Wszystkie treści w tym wiki, którym nie przyporządkowano licencji, podlegają licencji: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki