ACE

Adaptive Communication Environment

Grzegorz Marczyński

Email: gm153316@zodiac2.mimuw.edu.pl

  1. Co jest w środku
    1. Enkapsulacja funkcji systemowych w klasy C++
    2. Obsługa wielowątkowości, wieloprocesorowości
    3. Mechanizmy synchronizacji
    4. Demultiplexing zdarzeń i ich obsługa
    5. Tworzenie połączeń i serwisów sieciowych
    6. Dynamiczne konfigurowanie rozproszonych serwisów komunikacyjnych
    7. Gotowe do użycia schematy wspomagające tworzenie serwisów wyższego poziomu
  2. Platformy
    1. Win32 (WinNT 3.5.x i 4.x i Win95 z MSVC++ lub Borland C++)
    2. UNIX (np. SunOS 4.x, Solaris 2.x, SGI IRIX 5.x i 6.x, HP-UX 9.x i 10.x, OSF/1 aka. DEC UNIX, AIX 4.x, Linux, SCO, UnixWare, NetBSD i FreeBSD),
    3. systemy czasu rzeczywistego (np. VxWorks, Chorus, LynxOS, and pSoS)
    4. MVS OpenEdition
  3. Budowa warstwowa (rys 1)
    1. Warstwa zależna od systemu
      1. Właściwie nie należy do ACE - Win32, UNIX
    2. Enkapsulacja funkcji systemowych w C++ (C++ wrappers) / IPC_SAP
      1. Jednolity interfejs bez względu na platformę systemową
      2. Pokrywa następujące usługi systemowe:
        1. Wielowątkowość i synchronizację
        2. Komunikację międzyprocesową
        3. Demultiplexing zdarzeń
        4. Łączenie dynamiczne
        5. Pamięć dzieloną i pliki-mapy pamięci
      3. Kategorie klas:
        1. IPC_SAP (rys 2) - lokalne i zdalne IPC (gniazdka, TLI, łącza FIFO, strumienie, łącza nazwane)
          1. SOCK_SAP (rys 3) - protokoły Internetu ACE_SOCK*) i UNIXa (ACE_LSOCK*)
            1. *Dgram (datagramy - bez stałego połączenia) vs. *ACE_Stream (strumień - ze stałym połączeniem)
            2. ACE_*_Acceptor (tworzenie połączeń ) vs. *Stream (dające dwukierunkowy przepływ danych)
            3. Zalety: wczesne wykrycia błędów "złego typu", niezależność od platformy, mniej kodu
            4. Przykład użycia: Użycie klasy ACE_SOCK_Dgram_Bcast do rozgłoszenia wiadomości do wszystkich serwerów nasłuchujących na podanym numerze portu w lokalnej sieci:
            int

            main (int argc, char *argv[])
            {
            ACE_SOCK_Dgram_Bcast b_sap (sap_any);
            char *msg;
            unsigned short b_port;

            msg = argc > 1 ? argv[1] : "hello world\n";
            b_port = argc > 2 ? atoi (argv[2]) : 12345;

            if (b_sap.send (msg, strlen (msg),b_port) == ­1)
            perror ("can't send broadcast"), exit (1);

            exit (0);
            }
          2. TLI_SAP - System V Transport Layer Interface (analogicznie do SOCK_SAP, ale nie ma go w Win32)
          3. SPIPE_SAP - Szybkie lokalne IPC (Win32 - na łączach nazwanych, UNIX - łącze - STREAM, serwer connld ??)
          4. FIFO_SAP - UNIXowe łącza nazwane (FIFO)
        2. Pliki z mapą pamięci - Mem_Map
        3. System V IPC - np. semafory są bardziej intuicyjne i łatwiejsze w uzyciu (tylko signal i wait)
        4. Inicjalizacja Serwisów - Acceptor/Connector - tworzenie połączenia i inicjalizacja (strona pasywna i aktywna)
          1. Rozdziela proces tworzenia połączenia i inicjalizacji od samego korzystania z połączenia sieciowego. Acceptor umożliwia pasywne oczekiwanie na połączenie (strona serwera), Connector zaś implementuje aktywną stronę tworzenia połączenia
          2. Struktura:
            1. Service Handler -implementuje obsługę serwisu i udostępnia metodę open aktywującą usługę
            2. Acceptor - pasywne ustanawianie połączenia, tworzy peer_acceptor, który potem służy do transmisji danych, metoda open w Acceptor inicjalizuje peer_acceptor podłączając do odpowiedniego portu TCP pod lokalny adres IP
            3. Connector - inicjuje połączenie do zdalnego akceptora
            4. Dispatcher - przydziela żądania połączenia do Acceptora, pozwala, aby wiele obiektów typu Acceptor nasłuchiwało na połączenia; do Connectora Dispatcher podsyła informacje o zakończeniu procesu tworzenia połączenia, uruchamia metodę complete udostępnianą przez Connector - ma to sens jedynie przy asynchronicznym żądaniu uzyskania połączenia
        5. Mechanizmy współbieżności - wielowątkowość, wieloprocesowość, mechanizmy synchronizacyjne
          1. ACE_Mutex, ACE_Condition, ACE_Semapthore - enkapsulacja POSIX Pthreads
          2. Non-recursive locks - definicja sekcji krytycznej
          3. Recursive locks - możliwość rekurencji jeśli wątek jest właścicielem sekcji krytycznej w momencie ponownego wywołania
        6. Mechanizmy zarządzania pamięcią - dynamiczne przydzielanie i zwalnianie pamięci lokalnej i dzielonej
        7. Możliwa integracja z CORBĄ (np. jedno- i wielowątkowym Orbixem)
    3. Wzorce i schematy
      1. Reactor - rozwikływanie zdarzenia (demultiplexing) i wywoływanie obsługi
        1. Reactor obsługuje żądania usług, które przychodzą współbieżnie to aplikacji od wielu klientów. Każda usługa, którą aplikacja świadczy jest reprezentowana przed odrębny program obsługi zdarzenia (event handler), który jest odpowiedzialny za obsłużenie zdarzenia. Do rozwikłania, który program obsługi odpowiada za zdarzenie służy synchroniczny demultiplekser, za uruchomienie programu obsługi - initiation dispatcher.
        2. Struktura (rys. 4):
          1. Identyfikatory zasobów (handle) - oznaczają zasoby, którymi zarządza system operacyjny - połączenia sieciowe, otwarte pliki, zegary, obiekty synchronizacyjne.
          2. Synchroniczny rozwikływacz zdarzeń (Synchronous Event Demultiplekser) -blokuje wątek czekając na zdarzenia; kończy działanie, gdy jest możliwe wykonanie operacji na identyfikatorze zasobów bez blokowania
          3. Wywoływacz programów obsługi (Initiation Dispatcher) - określa interfejs do rejestracji, usuwania i wywoływania programów obsługi zdarzenia. Synchronous Event Demultiplexer przekazuje do Initiation Dispatcher informacje, kiedy zaszły zdarzenia, czyli: akceptacja, odczytywanie danych, wysyłanie danych, koniec czasu
          4. Program obsługi zdarzenia (event handler) - określa interfejs dla programów obsługi odpowiednich dla specyfikacji
          5. Konkretny program obsługi zdarzenia (concrete event handler) - implementuje konkretną obsługę zdarzenia
        3. Działanie (rys. 5)
        4. Implementacja:
          1. Initiation Dispatcher - tablica konkretnych programów obsługi, pętla główna: UNIX - select(), Win32 - poll(),
      2. Proactor - asynchroniczny demultiplekser i obsługa zdarzeń zakończenia
        1. Proaktor udostępnia rozwikływanie i wywoływanie wielu programów obsługi zdarzeń uaktywnianych przez zakończenie (completion) wywołań asynchronicznych
        2. Struktura (rys 6)
          1. Główny wątek (proactive Inititator) - byt w aplikacji, który wywołuje operacje asynchroniczną, rejestruje program obsługi zakończenia operacji (Completion Handler) i uruchamiacz (Completion Dispatcher) wraz z procesorem operacji asynchronicznych (asynchronous Operation Processor), który poinformuje o zakończeniu operacji
          2. Obsługa zakończenia wykonania (completion handler) - interfejs, który wraz z implementacją odrębną dla każdej aplikacji jest uruchamiany po zakończeniu asynchronicznej poeracji
          3. Operacja asynchroniczna (asynchronous operation) - służy do wywołania żądań (wej/wyj, zegar) w imieniu aplikacji; jak aplikacja wywoła operację asynchroniczną jest ona wykonywana bez obciążenia czasowego dla wątku aplikacji; po zakończeniu operacji asynchronicznej procesor operacji asynchronicznych powiadamia o tym Completion Dispatcher
          4. Procesor operacji asynchronicznych (asynchronous operation processor) - jednostka wykonująca operacje asynchroniczne, az do zakończenia; najczęściej implementowana przez system operacyjny
          5. Uruchamiacz programu obsługi zdarzenia zakończenia (Completion Dispatcher) - jest odpowiedzialny za wywołanie programu obsługi zdarzenia, gdy zakończy się wykonywanie operacji asynchronicznej
        3. Działanie (rys. 7)
        4. Wady:
          1. Trudności z odpluskwianiem
          2. Brak kontroli nad kolejnością wykonań zleconych operacji asynchronicznych
        5. Implementacja:
          1. API do wywołań
          2. Procesor Operacji Asynchronicznych - współczesne systemy operacyjne (WinNT, POSIX) wspomagają wywołania asynchroniczne, ale jeśli tak nie jest, to można użyć jednej z technik zastępczych: wątki dedykowane,
      3. Active_Object - asynchroniczne wykonywanie metod (oddzielenie wywołania od wykonania)
        1. Active Object rozprzęga wykonanie metody od jej wywołania (metoda jest wykonywana w innym wątku niż nastąpiło wywołanie). W ten sposób osiąga się prostszą synchronizację dostępu do zasobów dzielonych z różnych wątków.
        2. Struktura (rys. 8)
          1. Interfejs klienta (client interface) - interfejs metod dostępnych dla klienta, wywołanie metody powoduje skonstruowanie i umieszczenie w kolejce obiektu metody do asynchronicznego wywołania
          2. Obiekty metod (method objects) - jest tworzony dla każdego wywołania metody z interfejsu klienta, każdy obiekt zawiera w sobie kontekst wywołania metody
          3. Kolejka aktywacyjna (activation queue) - kolejka priorytetowa zwierająca obiekty metod czekające na wywołanie, jest zarządzana przez Zarządcę/planera
          4. Zarządca/planer (scheduler) - "meta-obiekt", który zarządza kolejką aktywacyjną, wykonanie kolejnych metod zależy od warunkowych synchronizacji wątków wykonujących
          5. Reprezentacja zasobów (resource representation) - dzielony zasób, który jest modelowany przez Active Object; zazwyczaj definiuje właściwe metody, które dostępne są przez interfejs klienta; może również zawierać inne metody pomocnicze dla zarządcy, aby określić kolejnośc wykonania metod z kolejki
          6. Identyfikator wyniku (return handle) - jest zwracany, gdy metoda jest wywoływana z interfejsu klienta; umożliwia aplikacji odzyskanie wyniku funkcji
        3. Współdziałanie elementów składowych (rys. 9)
        4. Wady
          1. potencjalnie zwiększa liczbę przełączeń kontekstu, kopiowania danych i narzutów synchronizacyjnych
          2. trudności z odpluskwianiem z powodu niedeterminizmu zarządcy
      4. Service Configurator - możliwośc dynamicznego łączenia i rekonfiguracji serwisów
        1. Service Configurator udostępnia możliwość dynamicznego łączenia (explicit dynamic linking z SunOS), rozszerza funkcjonalność konfiguracji "demonów" (inetd na UNIX, Service Control Menager w WinNT) wspomagając statyczną i dynamiczną konfigurację współbieżnego, wielo serwisowego oprogramowania komunikacyjnego, wiadomości przychodzące do zdefiniowanych portów przydziela do wyspecyfikowanych w aplikacji programów obsługi (dispatcher)
        2. Struktura (rys. 10)
          1. Service_Object - hierarchia dziedziczenia
            1. Shared_Object abstrakcyjna klasa główna - określa interfejs dla dynamicznie łączonych obiektów obsługi serwisu do przestrzeni adresowej aplikacji; udostępnia trzy abstrakcyjne metody: init, fini i info; zaimplementowanie tych metod w konkretnych podklasach Shared_Object zapewnia właściwe łączenie, inicjalizację, identyfikację i odłączanie serwisów w schemacie Service Configurator
            2. Service_Object podklasa abstrakcyjna - podklasa Shared_Object i Event_Handler; w konkretnych podklasach należy zaimplementować metody suspend i resume, które tu są abstrakcyjne; metody te są automatycznie wywoływana przez Sevice Configurator w odpowiedzi na zdarzenia zewnętrzne; dodatkowo konkretna podklasa musi zaimplementować metody init, fini, info i get_handle, co wynika z definicji nadklas (Shared_Object i Event_Handler)
            3. Specyficzne dla aplikacji konkretne podklasy - definiuje sześć ww metod i implementuje funkcje specyficzne dla danej aplikacji
          2. Service Repository - aby zapewnić swobodną możliwość obsługiwania wielu serwisów Service Repository przechowuje opisy wszystkich serwisów (jako znaki ASCII) oraz obiekty instancjonujące konkretne podklasy Service_Object; dla każdego obiektu przechowuje wskaźniki do kodu niezależnego od aplikacji, co umożliwia ładowanie, inicjalizację, zawieszanie, wznawianie i odwoływanie obiektów dynamicznie (bądź statycznie oczywiście); dla łączonych dynamicznie obiektów Service Repository trzyma identyfikator pliku (otwartego) zawierającego obiekt dynamiczny; dostępny jest również iterator umożliwiający swobodny dostęp do wszystkich trzymanych obiektów bez naruszania hermetyzacji
          3. Service Config - umożliwia dynamiczną lub statyczną konfigurację przechowywanych w Service Repository usług; używa pliku konfiguracyjnego (np.: svc.conf); każda aplikacja może być skojarzona z konkretnym plikiem svc.conf , ale jeden plik konfiguracyjny może obsługiwać wiele aplikacji na raz
            1. Gramatyka opisująca plik svc.conf:
          <svc­config­entries> ::=
          svc­config­entries svc­config­entry
          | NULL
          <svc­config­entry> ::= <dynamic> | <static>
          | <suspend> | <resume> | <remove>
          | <stream> | <remote>
          <dynamic> ::= DYNAMIC <svc­location>
          [ <parameters­opt> ]
          <static> ::= STATIC <svc­name>
          [ <parameters­opt> ]
          <suspend> ::= SUSPEND <svc­name>
          <resume> ::= RESUME <svc­name>
          <remove> ::= REMOVE <svc­name>
          <stream> ::= STREAM <stream_ops>
          '{' <module­list> '}'
          <stream_ops> ::= <dynamic> | <static>
          <remote> ::= STRING '{' <svc­config­entry> '}'
          <module­list> ::= <module­list> <module>
          | NULL
          <module> ::= <dynamic> | <static>
          | <suspend> | <resume> | <remove>
          <svc­location> ::= <svc­name> <type>
          <svc­initializer> <status>
          <type> ::= SERVICE_OBJECT '*' | MODULE '*'
          STREAM '*' | NULL
          <svc­initializer> ::= <object­name>
          | <function­name>
          <object­name> ::= PATHNAME ':' IDENT
          <function­name> ::= PATHNAME ':' IDENT '(' ')'
          <status> ::= ACTIVE | INACTIVE | NULL
          <parameters­opt> ::= STRING | NULL

        3. Działanie (rys. 11)

      5. Adaptive Service Executive (ASX) - upraszcza tworzenie oprogramowania komunikacyjnego przy wykorzystaniu wielu mechanizmów niskiego i wysokiego poziomu dostępnych bibliotece ACE
        1. Możliwości ASX
          1. Dowolny typ i liczba serwisów związanych z aplikacją
          2. Używany jest Service Configurator, więc czas i sposób instalowania i konfiguracji serwisów jest dowolny
          3. W ASX usługi mogą być udostępniane przez różnorodne typy procesów i wątków; poprzez oddzielenie funkcjonowania usługi od jej wywołania ASX udostępnia cały wachlarz możliwości przebiegu wykonania serwisu
          4. ... jak całe ACE
          5. Strumienie (Stream Class Category) (rys. 12) - Obiekty umożliwiające aplikacjom współpracę i wykonywanie serwisów wewnątrz ASX. Obiekt Stream zawiera serie wewnętrznie połączonych obiektów Module, które mogą być łączone podczas instalacji lub dynamicznie w czasie wykonania. Modules są obiektami służącymi do dekompozycji architektury rozproszonej aplikacji na warstwy. Każda warstwa implementuje grupę powiązanych ze sobą (składających się na jakąś usługę) funkcji. Warstwa przeprowadzająca multiplexing i demultiplexing obiektów z wiadomościami między dwoma powiązanymi Streams jest implementowana przez obiekt Multiplexor - pojemnik C++ udostępniający mechanizmy do "routowania" wiadomości między modułami w zbiorze powiązanych strumieni. Każdy obiekt Module zawiera parę obiektów Task, które dzilą warstwę na stronę czytającą i piszącą (read-side & write-side). Task jest abstrakcyjną klasą, którą można ukonkretnić dla osiągnięcia celów specyficznych dla aplikacji.
          6. Stream Class - Definiuje interfejs do strumienia. Obiekt Stream zawiera dwustronny interfejs typu get/put, który umożliwia aplikacjom dostać się do stosu jednego lub wielu powiązanych hierarchicznie modułów (Module). Aplikacja może przesyłać i odbierać wiadomości poprzez wewnętrznie połączone moduły. Stream implementuje również interfejs typu push/pop umożliwiający dynamiczne dodawanie i usuwanie obiektów klasy Module.
          7. Module Class - Definiuje właściwą warstwę serwisów. Zawsze istnieją przynajmniej dwa podstawowe moduły Stream_Head i Stream_Tail.
            1. Stream_Head - klasa buforująca wiadomości między aplikacją a strumieniem
            2. Stream_Tail - klasa transformująca przychodzące siecią wiadomości na wyższy poziom, czytelny dla elementów wyższego rzędu w Stream oraz analogicznie zamieniająca wewnątrzstrumieniowy format wiadomości na pakiety sieciowe przy pisaniu
          8. Task Abstract Class - definiuje stronę piszącą i czytającą poprzez implementacje abstrakcyjnych funkcji (open, close, put i svc)
          9. Multiplexor Class - obsługuje połączenia i rozgałęzienie strumieni
  4. Przykład zastosowania
    1. Serwer logujący
    2. The ACE Orb - TAO
  5. Dostępność:
  6. ftp://sunsite.icm.edu.pl/pub/programming/ace/

    http://www.cs.wustl.edu/~schmidt/ACE.html

  7. Bibliografia