32
Systemy rozproszone W. Bartkiewicz Wykład 5. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej – zdalne obiekty Część 2

Systemy rozproszone

  • Upload
    marty

  • View
    38

  • Download
    0

Embed Size (px)

DESCRIPTION

Uniwersytet Łódzki Katedra Informatyki. W. Bartkiewicz. Systemy rozproszone. Wykład 5. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej – zdalne obiekty Część 2. Katedra Informatyki. Ewolucja COM. Katedra Informatyki. COM Interfejsy. - PowerPoint PPT Presentation

Citation preview

Page 1: Systemy rozproszone

Systemy rozproszone

W. Bartkiewicz

Wykład 5. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej – zdalne obiekty

Część 2

Page 2: Systemy rozproszone

Ewolucja COM

Page 3: Systemy rozproszone

COMInterfejsy

• COM korzysta z modelu obiektu zdalnego. Obiekty COM umieszczane mogą być: – w procesie klienta,

– w procesie na tej samej maszynie co klient,

– w procesie na maszynie zdalnej.

• Podobnie jak CORBA, COM skupia się na realizacji interfejsów. Obiekt COM jest generalnie realizacją interfejsu. Jeden obiekt może realizować kilka interfejsów.

• Do definiowania interfejsów wykorzystywany jest język opisu interfejsu Microsoft IDL (MIDL).

• W przeciwieństwie do CORBY interfejsy COM mają charakter binarny. Są to tablice wskaźników do funkcji będących jego częściami.

Page 4: Systemy rozproszone

COMInterfejsy binarne i zależne od języka

Specyfikacja IDL

Kompilator z IDL na interfejs

Wskaźniki do funkcji

Tablica funkcji

Interfejsy binarne

Kompilator z IDL na język

Definicje klas Javy

Definicje klas C++

Prototypy CKompilator konkretnego

języka

Interfejsy zdefiniowane

w języku

Page 5: Systemy rozproszone

COMInterfejsy

• W środowisku CORBA standaryzacja interfejsów odbywa się na poziomie źródłowym, tzn. standardowy charakter ma IDL oraz odwzorowanie jego specyfikacji na dany język programowania.

• W COM standaryzacja odbywa się na poziomie binarnym. Kompilator interfejsów generuje standardową postać binarną interfejsu, która wykorzystana może być w dowolnym języku programowania.

• Każdy interfejs COM ma jednoznaczny 128 bitowy identyfikator, zwany identyfikatorem interfejsu (IID – Interface Identifier). Każdy IID jest globalnie jednoznaczny, tzn. nie ma dwu interfejsów o tym samym IID. Generowany jest na podstawie adresu interfejsu sieciowego danego komputera, czasu oraz dużej liczby losowej. Prawdopodobieństwo wygenerowania dwu takich samych IID jest praktycznie zerowe.

• Każda klasa obiektu COM również posiada jednoznaczny identyfikator klasy (CLSID – Class Identifier), tworzony na tej samej zasadzie co UUID.

Page 6: Systemy rozproszone

COMInterfejsy

• W środowisku CORBA obiekty funkcjonują w permanentnie działających procesach. W środowisku COM, odmiennie – obiekty mają charakter tymczasowy. Tworzone są z chwilą gdy klient żąda dostępu do obiektu, gdy zabraknie klientów odwołujących się do obiektu, następuje jego likwidacja.

• Czas życia obiektu COM zarządzany jest na zasadzie zliczania odwołań. Klienci powinni zwiększać licznik odwołań za każdym razem, gdy pobierają nowe odniesienie do obiektu. Gdy odniesienie przestaje być potrzebne, licznik odwołań powinien być przez klientów zmniejszany.

• Wszystkie obiekty COM realizują ten sam interfejs standardowy IUnknown.– Interfejs ten stanowi początkowy uchwyt do obiektu po jego utworzeniu.

– Zawiera funkcje AddRef i Release, zarządzające licznikiem odwołań.

– Zawiera funkcję QueryInterface, która pozwala pobrać odniesienie do innego z interfejsów realizowanych przez obiekt COM.

Page 7: Systemy rozproszone

COM Przykładowy interfejs IDL

import "unknwn.idl";

[ object, uuid (7223BBFD-8F42-43e7-92D9-5080991112C7) ]interface ISum : IUnknown{

HRESULT Sum([in] int x, [in] int y, [out, retval] int* retvl);};

Page 8: Systemy rozproszone

COM Implementacja obiektu COM

#include "component.h” //wygenerowany przez MIDL zawiera deklarację interfejsu ISum w C++

const CLSID CLSID_MathComp ={0xcec2b111, 0xa70f, 0x41ac, {0xab, 0xb9, 0xc, 0x2, 0x43, 0xbe, 0xae,0x49}};

class CMathComp : public ISum {public:

ULONG __stdcall AddRef();ULONG __stdcall Release();HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);

HRESULT __stdcall Sum(int x, int y, int* retvl);

CMathComp(): m_cRef(1) { g_cLocks++; }~CMathComp() { g_cLocks--;}

private:ULONG m_cRef;

};

Page 9: Systemy rozproszone

COM Implementacja obiektu COM

ULONG CMathComp::AddRef() {return ++m_cRef;

}

ULONG CMathComp::Release() {if ( --m_cRef != 0 ) return m_cRef;delete this;return 0;

}

HRESULT CMathComp::QueryInterface(REFIID riid, void** ppv) {if ( riid == IID_IUnknown ) *ppv = (IUnknown*) this;else if ( riid == IID_ISum ) *ppv = (ISum*)this;else { *ppv = NULL; return E_NOINTERFACE;}AddRef();return S_OK;

}

HRESULT CMathComp::Sum(int x, int y, int* retvl) {*retvl = x + y;return S_OK;

}

Page 10: Systemy rozproszone

COMInterfejsy

Page 11: Systemy rozproszone

COMFabryki klas

• Dla tworzenia obiektów COM, powłoka komponentu powinna dostarczać tzw. fabryki klas, tj. specjalnego obiektu COM, który utworzy właściwy obiekt.

• Fabryki klas implementują standardowy interfejs COM IClassFactory. Głównym elementem tego interfejsu jest funkcja CreateInstance, której zadaniem jest stworzenie obiektu.

Page 12: Systemy rozproszone

COM Implementacja fabryki klas

class CFactory: public IClassFactory {public:

ULONG __stdcall AddRef();ULONG __stdcall Release();HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);

HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, REFIID riid, void** ppv);

HRESULT __stdcall LockServer(BOOL bLock);

CFactory(): m_cRef(1) { g_cLocks++; }~CFactory() { g_cLocks--; }

private:

ULONG m_cRef;

};

Page 13: Systemy rozproszone

COM Implementacja fabryki klas

ULONG CFactory::AddRef() {return ++m_cRef;

}

ULONG CFactory::Release() {if ( --m_cRef != 0 )

return m_cRef;delete this;return 0;

}

HRESULT CFactory::QueryInterface(REFIID riid, void** ppv) {if ( riid == IID_IUnknown )

*ppv = (IUnknown*) this;else if ( riid == IID_IClassFactory )

*ppv = (IClassFactory*) this;else {

*ppv = NULL;return E_NOINTERFACE;

}AddRef();return S_OK;

}

Page 14: Systemy rozproszone

COM Implementacja fabryki klas

HRESULT CFactory::CreateInstance(IUnknown* pUnknownOuter, REFIID riid, void** ppv) {

if ( pUnknownOuter )return CLASS_E_NOAGGREGATION;

CMathComp* pMathComp = new CMathComp();if ( !pMathComp )

return E_OUTOFMEMORY;

HRESULT hr = pMathComp->QueryInterface(riid, ppv);pMathComp->Release();

return hr;}

HRESULT CFactory::LockServer(BOOL bLock) {if ( bLock )

g_cLocks++;else

g_cLocks--;return S_OK;

}

Page 15: Systemy rozproszone

COMDziałanie klienta

• Klient tworzy obiekty COM, wykorzystując funkcję CoCreateInstance. Funkcja ta lokalizuje powłokę komponentu (serwer), pobiera fabrykę klas komponentu i tworzy obiekt COM.

• Klient oddziaływuje na obiektach COM a wykorzystaniem wskaźników do interfejsów implementowanych przez te obiekty, pobieranych z wykorzystaniem funkcji QueryInterface.

• Komponent dba Każde wywołanie QueryInterface zwiększa licznik odwołań (dba o to sam obiekt COM). Jeśli klient samodzielnie powiela uchwyt di obiektu, powinien ręcznie wywołać AddRef.

• Dla każdego wywołania QueryInterface lub AddRef, jeśli uchwyt do obiektu nie jest już potrzebny, klient powinien wywołać Release.

Page 16: Systemy rozproszone

COM Implementacja klienta

#include "component.h" // Wygenerowany Przez MIDLconst CLSID CLSID_MathComp ={0xcec2b111, 0xa70f, 0x41ac, {0xab, 0xb9, 0xc, 0x2, 0x43, 0xbe, 0xae, 0x49}};

void main() {IUnknown* pUnknown;ISum* pSum;HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);if ( FAILED(hr) ) { cout<<"Blad CoInitializeEx. "<<endl; return; }

hr = CoCreateInstance(CLSID_MathComp, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**) &pUnknown);

if ( FAILED(hr) ) { cout<<"Blad CoCreateInstance. "<<endl; return; }hr = pUnknown->QueryInterface(IID_ISum, (void**) &pSum);if ( FAILED(hr) ) { cout<<"IID_ISum nie jest obslugiwany."<<endl; return;}pUnknown->Release();

int sum;hr = pSum->Sum(2,3, &sum);if ( SUCCEEDED(hr) )

cout<<"2+3="<<sum<<endl;pSum->Release();CoUninitialize();

}

Page 17: Systemy rozproszone

COMRejestr i SCM

• Aby naprawdę uaktywnić obiekt, tzn. zapewnić jego utworzenie i umieszczenie w procesie, skąd może akceptować wywołania metod, COM korzysta z rejestru Windows oraz specjalnego procesu nazywanego kontrolerem usług (SCM – Service Control Manager).

• Każdy komponent COM musi zostać zarejestrowany w kluczu HKEY_CLASSES_ROOT\CLSID pod swoim CLSID. Opis w rejestrze obejmuje między innymi nazwę pliku (DLL lub EXE) zawierającego implementację klasy.

• Funkcja CoCreateInstance znajduje CLSID komponentu w rejestrze, konkretyzuje serwer (powłokę) obiektu, tzn. ładuje odpowiedni plik DLL lub uruchamia plik EXE i udostępnia komponent do obsługi wywołań klienta.

• Dla komponentów zdalnych środowisko COM (a właściwie w tym przypadku DCOM) przekazuje CLSID obiektu lokalnemu SCM, który w lokalnym rejestrze odnajduje maszynę serwera, oraz przekazuje CLSID kontrolerowi SCM na tej maszynie.

Page 18: Systemy rozproszone

COMOdwołania zdalne

• Dla klienta DCOM kontakt z obiektem zewnątrzprocesowym (lokalnym lub zdalnym) wygląda tak samo jak podczas wykonywania obiektów COM wewnątrzprocesowych we własnej przestrzeni adresowej.

• Po konkretyzacji obiektu zdalnego, środowisko DCOM przetacza jego interfejs na serwerze i zwraca klientowi, gdzie jest on przetaczany odwrotnie do pośrednika realizującego odwołania do obiektu.

• Po udostępnieniu interfejsu klientowi, środowisko COM praktycznie nie wykonuje żadnych dodatkowych operacji. Odwołania do metod obiektu zdalnego realizowane są niemalże poprzez natywne wywołania Windows RPC.

• Parametry i wartości powrotne dla wywołań obiektów zdalnych muszą być oczywiście przetaczane. Standardowy kod przetaczania generowany jest przez MIDL. Z plików generowanych przez MIDL należy wygenerować bibliotekę DLL i zarejestrować w opisie komponentu (tzw. szeregowanie standardowe). COM oferuje również możliwości definiowania przetaczania niestandardowego.

Page 19: Systemy rozproszone

COMOdwołania zdalne

Page 20: Systemy rozproszone

COMOdwołania zdalne

Page 21: Systemy rozproszone

COMBiblioteki typów

• Biblioteka typów (type library) jest odpowiednikiem magazynu interfejsów ze standardu CORBA. Biblioteka typów jest najczęściej kojarzona z aplikacją lub komponentem składającym się z różnych obiektów klas.

• Kompilowana jest przez MIDL ze specjalnych deklaracji w opisie interfejsu. Zawiera binarną wersję interfejsów klasy COM, a także definiuje ich metody, parametry i zwracane typy.

• Może być ona przechowywana w komponencie (jak inne zasoby) lub w odrębnym pliku. Jeśli komponent ma korzystać z biblioteki typów, musi być ona zarejestrowana w jego opisie w rejestrze Windows.

• Biblioteka typów używana jest przede wszystkim do ścisłego określenia sygnatury metody.

• Narzędzia programowania korzystają z bibliotek typów również w celu pomocy w opracowaniu programu, na przykład wyświetlając w wygodnej postaci interfejsy na ekranie.

Page 22: Systemy rozproszone

COM Dodanie biblioteki typów do interfejsu

import "unknwn.idl";

[ object, uuid(10000001-0000-0000-0000-000000000001) ]interface ISum : IUnknown{ HRESULT Sum(int x, int y, [out, retval] int* retval);}

[ uuid(10000003-0000-0000-0000-000000000001), helpstring("Inside COM+ Component Type Library"), version(1.0) ]library Component{ importlib("stdole32.tlb"); interface ISum;

[ uuid(10000002-0000-0000-0000-000000000001) ] coclass MathComp { interface ISum; }};

Page 23: Systemy rozproszone

COM Klient korzystający z biblioteki typów

#define _WIN32_DCOM

//#import "component.tlb" no_namespace //skompil. przez MIDL biblioteka typow#import "component.dll" no_namespace //jeśli biblioteka typow w komponencie

#include <iostream.h>

void main(){ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ISumPtr myRef(__uuidof(MathComp)); int result = myRef->Sum(5, 13); cout << "5 + 13 = " << result << endl; myRef = NULL; CoUninitialize();}

Page 24: Systemy rozproszone

COMAutomatyzacja

• COM umożliwia również dynamiczne wywołania metod obiektów. Obiekty, których zamówienia wywołań mają być budowane w fazie wykonania programu, muszą realizować interfejs standardowy IDispatch. Interfejs ten podobny jest do interfejsu dynamicznych wywołań DII w standardzie CORBA.

• Obiekty COM realizujące interfejs IDispatch nazywamy obiektami automatyzacji lub automatyzmu (automation objects). Mogą one realizować czysty disp-interfejs, lub udostępniać również własne interfejsy niestandardowe. Mówimy wówczas o tzw. interfejsach dualnych.

• W obiektach automatyzacji możliwe jest również definiowanie własności.

• Metody interfejsu IDispatch korzystają dla parametrów ze standardowych typów danych (przede wszystkim typ VARIANT). Mogą więc być przetaczane przy pomocy standardowej biblioteki szeregującej i biblioteki typów, niemal bez żadnej dodatkowej pracy programisty (tzw. szeregowanie z biblioteką typów).

Page 25: Systemy rozproszone

COM Interfejs serwera automatyzacji

[ object, uuid(10000001-0000-0000-0000-000000000001), dual ]interface ISum : IDispatch{

[id(1)] HRESULT Sum([in] int x, [in] int y, [out, retval] int* retvl);}

• [id(1)] jest deklaracją tzw. DISPID, identyfikatora metody, który wykorzystywany będzie do dynamicznego jej wywołania. DISPID mogą mieć również właściwości.

• Musi mieć on charakter jednoznaczny (wszystkie metody i właściwości muszą mieć różne identyfikatory).

• Obiekt musi odpowiednio implementować interfejs IDispatch, pozwalający na wywołanie metody poprzez podanie jej DISPID oraz zawierający operacje wspomagające wywołania dynamiczne.

Page 26: Systemy rozproszone

COM Interfejs IDispatch

interface IDispatch : IUnknown{ // Czy obsługujesz informacje o typie? HRESULT GetTypeInfoCount(

[out] UINT* pctinfo ); // Zwraca wskaźnik do informacji o typie twojego obiektu. HRESULT GetTypeInfo(

[in] UINT iTInfo,[in] LCID lcid, [out] ITypeInfo** ppTInfo);

// Zwraca DISPID metody.

HRESULT GetIDsOfNames( [in] REFIID riid, [in, size_is(cNames)] LPOLESTR* rgszNames,

[in] UINT cNames, [in] LCID lcid, [out, size_is(cNames)] DISPID* rgDispId);

// Wywołuje metodę. HRESULT Invoke( [in] DISPID dispIdMember, [in] REFIID riid, [in] LCID lcid, [in] WORD wFlags, [in, out] DISPPARAMS* pDispParams, [out] VARIANT* pVarResult,

[out] EXCEPINFO* pExcepInfo, [out] UINT* puArgErr);};

Page 27: Systemy rozproszone

COM Implementacja serwera automatyzacji

HRESULT CInsideCOM::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) {

if(riid != IID_NULL)return DISP_E_UNKNOWNINTERFACE;

return DispGetIDsOfNames(m_pTypeInfo, rgszNames, cNames, rgDispId);}

HRESULT CInsideCOM::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {

if(riid != IID_NULL)return DISP_E_UNKNOWNINTERFACE;

return DispInvoke(this, m_pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);

}

• W większości przypadków funkcje interfejsu IDispatch implementowane są z wykorzystaniem funkcji pomocniczych biblioteki COM, przeszukujących bibliotekę typów. Możliwa jest jednak implementacja niestandardowa.

Page 28: Systemy rozproszone

COM Dynamiczne wywołanie metody

IDispatch* pDispatch;

OLECHAR* name = L"Sum";DISPID dispid;pDispatch->GetIDsOfNames(IID_NULL,&name,1,GetUserDefaultLCID(),&dispid);

VARIANTARG SumArgsPos[2];VariantInit(&SumArgsPos[0]);SumArgsPos[0].vt = VT_I4;SumArgsPos[0].lVal = 7;VariantInit(&SumArgsPos[1]);SumArgsPos[1].vt = VT_I4;SumArgsPos[1].lVal = 2;

VARIANT result;VariantInit(&result);DISPPARAMS Params1 = { SumArgsPos, NULL, 2, 0 };if(

FAILED(pDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &Params1, &result, NULL, NULL))

)cout << "pDispatch->Invoke() failed" << endl;

Page 29: Systemy rozproszone

COMPunkty połączenia

• Podstawowy model komunikacyjny COM opiera się na standardowych wywołaniach metod obiektów zdalnych. W niektórych sytuacjach może być on jednak niewystarczający.

• Jeśli sytuacja wymaga komunikacji dwustronnej, tzn. aby obiekt poinformował klienta o zajściu pewnego zdarzenia i zażądał jego obsłużenia, możliwe jest to dzięki realizacji mechanizmu tzw. punktów połączeń.

• Schemat działania jest następujący:– Obiekt definiuje interfejs komunikacyjny, jakiego wymaga aby przesłać

klientowi komunikat o zdarzeniu. Interfejs ten nazywamy źródłowym (source interface) lub wychodzącym (outgoing interface).

– Klient, który chce otrzymywać zdarzenia implementuje wymagany przez obiekt interfejs źródłowy. Implementację taką nazywamy ujściem (sink).

– Obiekt z kolei musi implementować standardowe interfejsy COM obsługujące punkty połączeń (najważniejszy to interfejs IConnectionPoint). Interfejs ten zawiera funkcje umożliwiające przekazanie obiektowi przez klienta uchwytu do ujścia (wskaźnika do realizacji interfejsu źródłowego).

– Klient po utworzeniu obiektu przekazuje mu wskaźnik do swojego ujścia.

Page 30: Systemy rozproszone

COMPunkty połączenia

Interfejs źródłowy Obiekt dołączalny

Ujście

Klient

Page 31: Systemy rozproszone

COMGrupowe rozsyłanie zdarzeń

Page 32: Systemy rozproszone

COMOdbieranie zdarzeń od wielu obiektów