DCOP - komunikačný protokol v KDE

23.5.2004 Rudo Thomas

Obsah

  1. Obsah
  2. Úvod
  3. Fungovanie DCOPu
  4. Pridanie DCOP rozhrania, IDL
  5. Príklad v shelli
  6. Záver, postrehy
  7. Zdroje

Úvod

DCOP je veľmi jednoduchý protokol, ktorý v prostredí KDE slúži na komunikáciu (IPC/RPC) medzi aplikáciami. Používajú ho prakticky všetky programy, ktoré sú súčasťou distribúcie KDE, napríklad panel (kicker), window manager (kwin). DCOP sprístupňuje rozhrania aplikácii nielen ďalším KDE programom, ale napríklad aj shell skriptom. Tiež sa používa v KParts, ktorými sa v KDE vnorujú časti aplikácii do iných aplikácii.

Pre jednoduchú ilustráciu je dobré spustiť program kdcop, ktorý zobrazí strom všetkých spustených programov, ktoré DCOP podporujú, spolu s objektami a metódami, ktoré sú k dispozícii.

Fungovanie DCOPu

DCOP je pomerne rýchly a jednoduchý protokol, ktorý pracuje nad socketami. Používa knižnicu libICE (Inter Client Exchange), ktorá je súčasťou X11. V budúcnosti sa plánuje odstrániť akákoľvek závoslosť KDE na X Window System, takže je pravdepodobné, že niekto naprogramuje náhradu za libICE.

Komunikáciu medzi programami sprostredkúva dcopserver, všetky programy (klienti) sú si rovnocenní. Klient má vrámci servera jednoznačný identifikátor, prípadne môže komunikovať anonymne. Identifikátorom býva spravidla meno programu spojené pomlčkou s číslom procesu (napr. konsole-5942). V prípade, že ide o program, ktorý zakazuje beh viacerých svojich inštancii (dedí po triede KUniqueApplication), je jeho identifikátorom len jeho meno (príkladom je panel kicker). Anonymne pripojený klient smie komunikovať smerom od seba, nedajú sa mu adresovať žiadne volania.

Trieda DCOPClient implementuje DCOP klienta. Inštancia sa tradične získava z návratovej hodnoty metódy KApplication::dcopClient(). Pripojenie na server realizuje DCOPClient::attach(), identifikátor sa dá zmeniť pomocou DCOPClient::registerAs(const QCString&).

Jeden klient môže cez DCOP sprístupniť viacero objektov, pričom každý môže implementovať iné rozhranie. Pri volaní treba vždy uviesť

Všetky identifikátory sa prenášajú ako reťazce. Výber správneho klienta zisťuje server; výber objektu rieši DCOPObject; meno metódy sa nezmenené predá virtuálnej metóde DCOPObject::process( ... ), ktorú musí užívateľ predefinovať (viď nižšie).

Existujú dva základné druhy volania: blokujúce a neblokujúce. Ide o klasickú terminológiu: pri blokujúcom volaní volajúci čaká, kým volaný vykoná požadovanú akciu. Takéto volanie môže mať návratovú hodnotu. Pri neblokujúcom volaní volajúci nečaká, ale ani nemá možnosť zistiť, ako volanie dopadlo (detekované sú jedine chyby pri komunikácii cez DCOP).

Neblokujúce volanie uskutočníme zavolaním metódy DCOPClient::send( ... ), ktorá má okrem troch adresátov (klient, objekt, metóda) aj parameter data typu QByteArray. Ide o pole bajtov, do ktorého sú pomocou operátora << doslova "nasypané" všetky argumenty volanej metódy. Typovú kontrolu nad takto usporiadanými dátami prekladač pochopiteľne vykonať nemôže, takže ak by programátor písal takéto volania ručne, musel by byť nesmierne opatrný. V praxi sa však používa IDL prekladač, o ktorom ešte bude reč. Podobne sú realizované blokovacie volania. Metóda DCOPClient::call( ... ), ktorá ich realizuje, má o dva parametre viac: po úspešnom volaní vráti volajúcemu typ návratovej hodnoty a samotnú návratovú hodnotu opäť zabalenú v QByteArray. Príklady sa dajú nájsť v zdrojoch.

Cez triedu DCOPClient je možné komunikovať smerom von - volať metódy iných klientov. Na komunikáciu opačným smerom, čiže sprístupnenie množiny metód (rozhrania) je treba vytvoriť inštanciu triedy DCOPObject. Identifikátor mena objektu, pod ktorým bude v DCOPe prístupný, sa nastavuje v konštruktore. Akékoľvek DCOP volanie tohoto objektu potom vyvolá virtuálnu metódu process na tejto inštancii.

Na implementáciu vlastných metód treba predefinovať práve virtálnu metódu process, ktorá dostane reťazec obsahujúci meno volanej DCOP metódy (toto obsahuje typy argumentov), pole bajtov QByteArray s argumentami a priestor pre uloženie návratovej hodnoty spolu s jej typom. Za zavolanie správnej metódy ako aj za správnu konverziu neformátovaných dát na príslušné typy argumentov a návratovej hodnoty je úplne zodpovedná práve metóda process. Skoro nikdy ju však netreba písať ručne, ako uvidíme v ďalšej kapitole.

Pridanie DCOP rozhrania, IDL

Je prirodzené sprístupňovať už existujúce rozhranie aplikácie cez DCOP. Preto je v KDE zvykom inštancie tried v programe spolu s ich metódami namapovať 1:1 na DCOP objekty a metódy. Najjednoduchšia cesta, akou dosiahnuť tento efekt, je napísať virtuálneho potomka DCOPObject, ktorý deklaruje zverejnené metódy ako čisto virtuálne a implementuje metódu process. Tá na základe svojich argumentov zavolá príslušnú metódu so správne extrahovanými argumentami. Potom stačí virtuálne dediť po tejto triede - metóda process potom zavolá skutočnú implementáciu vybraných metód. Príklad je v zdrojoch.

Samozrejme, práve uvedený postup sa dá zautomatizovať. Stačí napísať hlavičku triedy, interface. Generátory dcopidl a dcopidl2cpp vygenerujú skeleton: Zdrojový kód v C++, ktorý v tele metódy process z poľa bajtov správne skopíruje argumenty a zavolá príslušnú metódu. Výsledný objekt potom treba pridať do virtuálnych predkov triedy, ktorá metódy skutočne implementuje a v jej konštruktore volať konštruktor triedy DCOPObject s menom, pod ktorým bude objekt prístupný cez DCOP.

DCOP IDL (Interface Definition Language) sa len nepatrne líši od C++. Návratovou hodnotou môže byť okrem lubovoľného typu, ktorý sa dá zabaliť do QByteArray, aj špeciálna hodnota ASYNC. V C++ sa expanduje na void; jeden súbor je teda možné použiť aj v C++, aj ako základ pre IDL generátory. Z pohľadu implementujúcej triedy v prípade návratovej hodnoty ASYNC nejde o žiadnu zmenu oproti typu void. Zmení sa len typ volania na neblokujúce: volajúci DCOP klient nebude čakať na dobehnutie metódy.

dcopidl2cpp vygeneruje okrem skeletonu aj stub. Ide o triedu, ktorá umožnuje komunikovať s triedami v inom programe priamo, čiže nie cez metódy DCOPClient::call a DCOPClient::send. Metódy, ktoré presne zodpovedajú danému rozhraniu, fungujú opačne ako metóda process. Svoje argumenty zabalia do poľa bajtov a návratovú hodnotu rozbalia (pričom skontrolujú, či vrátený typ zodpovedá očakávaniam). Volajú spomínané metódy send, ak ide o ASYNC volanie, alebo call, inak.

Príklad v shelli

Na seminári sa rozoberal zaujímavý problém. Ako programovo premenovať záložku (tab) v konzole (konsole)? Napríklad by sa mohla záložka volať rovnako ako súbor, ktorý v nej upravujeme a podobne.

Program konsole má DCOP rozhranie, ktoré okrem iného umožňuje zistiť identifikátor aktuálne vybranej záložky (QString konsole::currentSession()) a tiež zmeniť jej zobrazované meno (názov objektu máme z predchádzajúceho volania, metóda má identifikátor renameSession(QString)).

Problém je ešte zistiť, ktorú bežiacu inštanciu programu konsole oslovovať. Program dcop, ktorý slúži práve na DCOP komunikáciu zo skriptov, umožňuje vypísať všetky. Stačí ako parameter uviesť "konsole-*" (podobne ako v prípade adresovania). Z vypísaných identifikátorov sa jednoducho zistia čísla príslušných procesov - nesledujú za mínusom. Postupným prechádzaním čisel rodičovských procesov, začínajúc od procesu shellu, v ktorom skript beží, musíme prísť k niektorému z procesov konsole. Ak sa skript nespustí spod tohoto programu, vypíše chybu.

Samotný skript je k dispozícii. Je napísaný v bashi.

Záver, postrehy

DCOP je značne jednoduchý, zato však pomerne rýchly protokol, ktorý slúži svojmu účelu - volaniu funkcii medzi programami KDE. Na pokročilejšie použitie, akým je napríklad posielanie multimedálnych dát, už nestačí. (Práve na "multimediálnu komunikáciu" v KDE zlúži MCOP.)

DCOP nerieši platformovú nezávislosť, čo sa týka umiestnenia argumentov funkcii a ich návratových hodnôt v poliach bajtov, ktoré sa prenášajú. Všetko zabezpečujú operátory << a >>, ktoré dedí trieda QByteArray. Tieto však závisia na cieľovej architektúre, takže napriek tomu, že je možné dosiahnuť, aby sa aplikácie bežiace na rôznych platformách spojili s tým istým DCOP serverom, ich vzájomná komunikácia fungovať nebude.

Vďaka veľmi jednoduchému sprístupňovaniu rozhraní je častokrát DCOP rozhranie zhodné s vnútorným rozhraním programu. Na jednej strane to umožňuje značné možnosti ovládania aplikácie zvonka, na strane druhej je však väčšinou toto vnútorné zohranie dokumentované iba v zdrojových súboroch, ak vôbec.

Zdroje