|
|
29行目: |
29行目: |
| デーモン(軽量サービスプロバイダ)とそれを利用したいソフトウェアが、必要なサービス以上のことを知らなくても通信できるようにするためによく利用される。<br> | | デーモン(軽量サービスプロバイダ)とそれを利用したいソフトウェアが、必要なサービス以上のことを知らなくても通信できるようにするためによく利用される。<br> |
| <br> | | <br> |
| Qtは、D-Busと対話するためのクラスとツールのセットを提供している。<br>
| | また、Qtは、D-Busと対話するためのクラスとツールのセットを提供している。<br> |
| <br><br>
| |
| | |
| == D-Busの基礎 ==
| |
| ==== D-Busとは ====
| |
| D-Busは、<u>メッセージ</u>を<u>オブジェクト</u>に届ける仕組みである。<br>
| |
| メッセージはデータであり、オブジェクトはデータの受け手であるプログラムのことである。<br>
| |
| <br> | | <br> |
| D-Busのメッセージには、手続き呼び出し(METHOD_CALL)、手続きの戻り値(METHOD_RETURN)、エラー(ERROR)、シグナル(SIGNAL)の4種類がある。<br> | | D-Busの詳細を知りたい場合は、[[設定 - D-Bus]]のページを参照すること。<br> |
| <br>
| |
| 手続き呼び出し(METHOD_CALL)と手続きの戻り値(METHOD_RETURN)はペアで使用されており、<br>
| |
| <u>他のプロセスが提供するサービス機能を関数の呼び出しのように使用することができる</u>という一種のRPC(Remote Procedure Call)のようなものとして扱うことができる。<br>
| |
| <br>
| |
| ただし、D-Busは同一PC上のIPCに特化しており、RPCのようなネットワークを介した異なるPC間の通信は原則としてサポートしていない。<br>
| |
| <br>
| |
| シグナル(SIGNAL)は、片方向の一斉通知として使用することができ、ネットワークが落ちた時、USBデバイスの検出、再起動の要請等の通知メカニズムとして多用されている。<br>
| |
| <br>
| |
| オブジェクトは、<u>サービス</u>に内包された<u>操作対象を指す名前</u>である。<br>
| |
| <br>
| |
| ==== D-Busサービス名とは ====
| |
| D-Busにおけるサービス名は、サービス提供プロセスがD-Busサーバに接続する時に登録する名前のことである。<br>
| |
| "org.freedesktop.DBus"や"org.bluez"等のように、<code>.(コロン)</code>区切りの文字列(慣習として、サービスプログラム開発元の公式ドメイン)が使用される。<br>
| |
| <br>
| |
| ※注意<br>
| |
| D-Busサービス名は、<u>バス名</u>、<u>コネクション名</u>等、異なる名前で呼ばれる場合もある。<br>
| |
| D-Busの仕様としては、<u>バス名</u>が正式名称であり、名前を明示的に指定したバス名を<u>サービス名</u>と呼ぶこともある。<br>
| |
| <br>
| |
| プロセスはサービス名を明示せずに、D-Busサーバに接続することも可能である。<br>
| |
| この場合、":1.128"のようにD-Busサーバが適当に生成した数字の羅列が割り当てられる。<br>
| |
| <br>
| |
| ==== D-Busオブジェクトとは ====
| |
| オブジェクトは、バス名(D-Busサービス名)に対して送られるメッセージに含まれる、そのバス名(D-Busサービス名)内におけるメッセージの宛先である。<br>
| |
| <code>/</code>から始まり、<code>/(スラッシュ)</code>区切りの文字列で表記されており、これを、<u>オブジェクトパス</u>、あるいは、<u>パス名</u>、<u>パス</u>と呼ぶこともある。<br>
| |
| <br>
| |
| 慣習として、パス名は、サービス名の<code>.</code>を<code>/</code>に置き換えた接頭辞(プレフィックス)を持たせる。<br>
| |
| <br>
| |
| 例えば、BlueZのbluetoothデーモンは、サービス名org.bluezを持つが、BlueZのオブジェクトは/org/bluez/hci0のような名前である。<br>
| |
| HCIインターフェースを複数持つシステムの場合、/org/bluez/hci1、/org/bluez/hci2のようなオブジェクト名により、どのインターフェースに対するメッセージかを識別することになる。<br>
| |
| <br>
| |
| サービスが持つオブジェクトの一覧は、イントロスペクト(Introspect)という機能により検索することができる。<br>
| |
| 例えば、BlueZ 5のサービスに対して、<code>dbus-send</code>コマンドを実行する。<br>
| |
| dbus-send --print-reply --system --dest=org.bluez / --type=method_call org.freedesktop.DBus.Introspectable.Introspect
| |
|
| |
| # 出力例
| |
|
| |
| ...略
| |
| </interface><node name="org"/></node>"
| |
| <br>
| |
| 上記の出力例のように、出力された<node name="org"/>の項目は、以下に示す内容を意味する。<br>
| |
| # バス名(D-Busサービス名)<code>org.bluez</code>のD-Busオブジェクト<code>/</code>に対して、
| |
| # 手続きメッセージ<code>org.freedesktop.DBus.Introspectable.Introspect</code>を送信した時、
| |
| # <code>/</code>の下には<code>org</code>というオブジェクトがあるというメッセージを受信した。
| |
| <br>
| |
| ==== D-Busインターフェース (D-Busメッセージ) ====
| |
| 上記セクションにあるような"org.freedesktop.DBus.Introspectable.Introspect"を手続きメッセージの例として扱っている。<br>
| |
| これは、freedesktop.orgで既定された標準メッセージの一部であるが、各サービスごとに独自のメッセージを実装することもできる。<br>
| |
| <br>
| |
| 例えば、BlueZ 5において、HCIインターフェースを検索可能状態にするメッセージは、以下に示すようなものになる。<br>
| |
| dbus-send --print-reply \
| |
| --system \
| |
| --dest=org.bluez \
| |
| /org/bluez/hci0 \
| |
| --type=method_call \
| |
| org.bluez.Adapter1.StartDiscovery
| |
| <br>
| |
| D-Busインターフェースは、オブジェクト指向の考えに基づいており、同じD-Busインターフェースに属する手続きは、異なるD-Busオブジェクト(サービス)間でも同じ機能として動作する。<br>
| |
| <br>
| |
| 例えば、イントロスペクト機能のorg.freedesktop.DBus.Introspectable.IntrospectというD-Busインターフェースは、<br>
| |
| org.freedesktop.DBusサービスの/オブジェクトに対しても、org.bluezサービスの/org/bluez/hci0オブジェクトに対しても、同様に動作する。<br>
| |
| <br>
| |
| ==== D-Busプロパティ ====
| |
| org.freedesktop.DBusの標準インターフェースとして、D-Busプロパティがある。(<u>プロパティ</u>と呼ぶこともある)<br>
| |
| D-Busプロパティは、<u>名前 + 値</u>のセットであり、これにより、D-Busオブジェクトの持つ状態や設定等を共通の枠組みで扱うことができる。<br>
| |
| <br>
| |
| D-Busプロパティのインターフェースはorg.freedesktop.DBus.Propertiesであり、<code>Get</code>メソッドや<code>Set</code>メソッド等が定義されている。<br>
| |
| 以下の例では、org.bluezサービス、/org/bluez/hci0オブジェクトの持つプロパティの一覧が表示される。<br>
| |
| dbus-send --print-reply \ # 相手からの応答を出力
| |
| --system \ # D-Busのタイプ (システムバスまたはセッションバス)
| |
| --dest=org.bluez \ # バス名 (D-Busサービス名)
| |
| /org/bluez/hci0 \ # D-Busオブジェクト名
| |
| --type=method_call \ # メッセージタイプ
| |
| # メソッドの場合は<code>method_call</code>、シグナルの場合は<code>signal</code>を指定する
| |
| # 省略した場合は、<code>signal</code>を指定したことになる
| |
| org.freedesktop.DBus.Properties.GetAll \ # D-Busインターフェース名(org.freedesktop.DBus.Properties)とメソッド名(GetAll)
| |
| string:org.bluez.Adapter1 # メソッドの引数
| |
| <br><br>
| |
| | |
| == バス ==
| |
| D-Busは、ソフトウェアが相互に通信するため、複数のメッセージバスを提供する。<br>
| |
| <br>
| |
| 各バスには独自の接続機能があり、異なるカテゴリーのメッセージを分離することができる。<br>
| |
| <br>
| |
| あるバスで送信されたメッセージは他のバスからアクセスできないが、同じバスに接続されたソフトウェアは全て互いに通信することができる。<br>
| |
| 任意のバスに複数のソフトウェアを同時に接続することができ、また、1つのソフトウェアが複数のバスに同時に接続することも可能である。
| |
| これにより、バスごとに異なるセキュリティポリシーを適用できると共に、グローバルメッセージとローカルメッセージの両方を効率的に共有することができる。<br>
| |
| <br>
| |
| D-Busは、2つの定義済みバス(<u>システムバス</u>と<u>セッションバス</u>)を予め用意されており、一般的なD-Busの使用方法をほぼカバーすることができる。<br>
| |
| * システムバス
| |
| *: ハードウェア管理等のシステムグローバルサービスに使用される。
| |
| *: これはユーザー間で共有され、通常、厳格なセキュリティ・ポリシーが付属しています。
| |
| *: <br>
| |
| * セッションバス
| |
| *: 各デスクトップセッション(ログインしているユーザ等)には、セッションバスが存在する。
| |
| *: これは、GUIソフトウェア等が最も頻繁に使用する傾向がある。
| |
| <br>
| |
| さらに、ソフトウェアは、必要に応じて複数の独自のバスを作成することができる。<br>
| |
| <br><br>
| |
| | |
| == メッセージ ==
| |
| メッセージは、バスにおける通信の基本単位である。<br>
| |
| <br>
| |
| TCP/IPのパケットと同様に、バスでやり取りされる情報は、全てメッセージで行われる。<br>
| |
| しかし、ネットワークのパケットとは異なり、D-Busの各メッセージには、送受信されるデータ1式が含まれていることが保証されている。<br>
| |
| <br>
| |
| メッセージには、送信されるデータだけでなく、送信者と受信者が誰であるかも記録されており、適切なルーティングを可能にする。<br>
| |
| メッセージは、メソッドコール、シグナルエミッション、メソッドの戻り値であり、エラー情報も含むことがある。<br>
| |
| <br><br>
| |
| | |
| == 名前空間とアドレス ==
| |
| 複数のソフトウェアが同一のバス上に存在し、1つのソフトウェアが複数のオブジェクトを提供してメッセージを送信することができるため、<br>
| |
| 特定の住宅やオフィスを一意に識別するのと同様に、任意のバス上の任意のオブジェクトを効果的かつ一意にアドレス指定する手段を持つことが必要である。<br>
| |
| <br>
| |
| インターフェース、サービス、オブジェクト名の3つの情報を組み合わせることにより、バス上の任意のオブジェクトに一意のアドレスを作成することができる。<br>
| |
| <br>
| |
| ==== インターフェイス ====
| |
| インターフェイスは、バス上に公表される呼び出し可能なメソッドとシグナルのセットである。<br>
| |
| <br>
| |
| インターフェースは、メッセージを渡すソフトウェアの間で、インターフェースの名前、パラメータ(もしあれば)、戻り値(もしあれば)を定義する"契約"を提供する。<br>
| |
| <br>
| |
| これらのメソッドは、インターフェイスを使用しているソフトウェアのメソッドやAPIに1対1で直接マッピングされることもある。(直接マッピングされないこともある)<br>
| |
| これにより、複数のソフトウェアが、内部の実装に関係なく、類似または同一のインターフェイスを提供することができ、<br>
| |
| 一方で、ソフトウェアは、ソフトウェアの内部設計を気にすることなく、これらのインターフェイスを使用できるようになる。<br>
| |
| <br>
| |
| インターフェイスは、文書化やコードの再利用を目的として、XMLで記述する。<br>
| |
| ユーザや開発者は、インターフェースのXML記述を参照できるだけでなく、開発者はXMLから自動生成されたクラスを使用することができる。<br>
| |
| このため、D-Busの使用は非常に簡単で、エラーが発生しにくくなる。(例. コンパイラがコンパイル時にメッセージの構文を確認することができる)<br>
| |
| <br>
| |
| ==== サービス ====
| |
| サービスとは、ソフトウェアとバスの接続を表すものである。<br>
| |
| <br>
| |
| ここでいうサービスとは、D-Busの用語でいうバス名に相当するものである。<br>
| |
| (<u>バス名という用語は、バス上の接続名であり、バスの名前ではない。</u>そのため、Qtのドキュメントで記載されているように、サービスという用語を使用する)<br>
| |
| <br>
| |
| これらは、複数のコンポーネントの名前空間を必要とする他の多くのシステムで見られるように、"逆ドメイン名"アプローチを使用することにより、一意に保たれる。<br>
| |
| KDEプロジェクトのソフトウェアが提供する多くのサービスでは、サービス名にorg.kdeというプレフィックスを使用している。<br>
| |
| そのため、セッションバスにおいて、org.kde.screensaverが宣伝されているのを見掛けるかもしれない。<br>
| |
| <br>
| |
| サービス名には、開発者の組織やソフトウェアのドメイン名を使用することを推奨する。<br>
| |
| 例えば、開発者のドメインがawesomeapps.org、ソフトウェアの名前がwickedwidgetの場合、バス上のサービス名はorg.awesomeapps.wickedwidgetとなる。<br>
| |
| <br>
| |
| ソフトウェアが複数のバスに接続している場合、または、同一のソフトウェアの複数のインスタンスが同時にアクティブになっている場合は、接続ごとに一意なサービス名を使用する必要がある。<br>
| |
| 多くの場合、プロセスIDをサービス名に付加することでこれを実現する。<br>
| |
| <br>
| |
| ==== オブジェクト ====
| |
| ソフトウェアは、バス上の複数のオブジェクトへのアクセスを宣伝する可能性が高い。<br>
| |
| <br>
| |
| オブジェクトとサービスの間のこの多対1の関係は、アドレスにパスコンポーネントを提供することで対応される。<br>
| |
| <br>
| |
| サービスに関連付けられた各パスは、異なる一意のオブジェクトを表す。(例. /MainInterface、/Documents/Doc1)<br>
| |
| 実際のパス構造は完全に任意であり、どのようなパスにするかは、サービスを提供するソフトウェア次第である。<br>
| |
| これらのパスは、他のソフトウェアにメッセージを送信するソフトウェアのために、オブジェクトを識別し、論理的にグループ化する方法を提供する。<br>
| |
| <br>
| |
| 一部のライブラリは、オブジェクトを適切に名前空間化するために、オブジェクトパスの先頭に"リバースドメイン"を付けてエクスポートする。<br>
| |
| これは、任意のサービスに参加するライブラリやプラグインではよくあることで、そのため、ソフトウェアや他のコンポーネントによりエクスポートされたオブジェクトとの全ての衝突を避けなければならない。<br>
| |
| しかし、KDEソフトウェアやライブラリでは、この方法は使用されていない。<br>
| |
| <br>
| |
| オブジェクトはインターフェースへのアクセスを提供しており、オブジェクトは同時に複数のインタフェースへのアクセスを提供することができる。<br>
| |
| <br>
| |
| ==== アドレスの例 ====
| |
| D-Busメッセージには、上記で記載したコンポーネントで構成されるアドレスが含まれており、正しいソフトウェア、オブジェクト、メソッドコールにルーティングされる。<br>
| |
| # 例. KRunnerのアドレス
| |
| org.kde.krunner /App org.kde.krunner.App.display
| |
|
| |
| org.kde.krunner : サービス
| |
| /App : オブジェクトへのパス
| |
| org.kde.krunner.App : オブジェクトがエクスポートするインターフェース
| |
| display : インターフェース内のメソッド
| |
| <br>
| |
| もし、/Appオブジェクトがorg.kde.krunner.Appインターフェースを提供するのみの場合(または、実装するサービスの中で表示メソッドが一意の場合)、これはアドレスとして同様に機能する。<br>
| |
| org.kde.krunner /App display
| |
| <br>
| |
| このようにして、可能性のあるそれぞれの宛先を一意かつ確実にアドレスで指定することができる。<br>
| |
| <br><br>
| |
| | |
| == メソッドとシグナル ==
| |
| バス上の任意のエンドポイントをアドレス指定する方法を使用して、メッセージを送受信する場合の可能性を検討する。<br>
| |
| <br>
| |
| ==== メソッド ====
| |
| 受信側のソフトウェアにおいて、メソッド(関数)を実行するために送信されるメッセージのことである。<br>
| |
| <br>
| |
| メソッドの呼び出しに失敗した場合(アドレスの間違い、または、要求されたソフトウェアが動作していない等の理由でメソッドが利用できない場合)、呼び出し側のソフトウェアにエラーが返る。<br>
| |
| <br>
| |
| メソッドの呼び出しに成功した場合、呼び出し元のソフトウェアにオプションの戻り値が返る。(戻り値が提供されない場合でも、成功メッセージが返る)<br>
| |
| このラウンドトリップにはオーバーヘッドがあり、パフォーマンスが重要なコードではこれを念頭に置くことが重要である。<br>
| |
| <br>
| |
| メソッド呼び出しは、常に呼び出し元のソフトウェアによって開始されて、結果として生じるメッセージは正確に1つの送信元アドレスと1つの送信先アドレスを持つ。<br>
| |
| <br>
| |
| ==== シグナル ====
| |
| シグナルはメソッドコールに似ているが、"逆方向"に発生すること、単一の宛先に縛られないことが特徴である。<br>
| |
| <br>
| |
| シグナルは、インターフェイスをエクスポートしているソフトウェアから発信されて、同一バス上のどのソフトウェアでも利用できる。<br>
| |
| これにより、ソフトウェアは、状態の変化やその他のイベントを、それらの変化を追跡するソフトウェアに自発的に知らせることができる。<br>
| |
| <br>
| |
| これは、Qtのシグナルとスロットの仕組みに似ており、これは、同じ機能のシステム版である。<br>
| |
| <br><br>
| |
| | |
| == D-Busコマンド ==
| |
| 以下の例では、Linuxでのシャットダウン、再起動、ログアウト等のD-Busサービスの一覧を取得している。<br>
| |
| dbus-send --print-reply=literal \
| |
| --system \
| |
| --dest=org.freedesktop.login1 \
| |
| /org/freedesktop/login1 \
| |
| --type=method_call \
| |
| org.freedesktop.DBus.Introspectable.Introspect
| |
| <br>
| |
| 以下の例では、D-Busサービスを使用してシャットダウンおよび再起動を実行している。<br>
| |
| # シャットダウン
| |
| dbus-send --print-reply=literal \
| |
| --system \ # バスタイプ
| |
| --dest=org.freedesktop.login1 \ # バス名(D-Busサービス名)
| |
| /org/freedesktop/login1 \ # D-Busオブジェクト名(オブジェクトパス)
| |
| # バス名(D-Busサービス)に送信するメッセージに含まれるそのバス名(D-Busサービス)内におけるメッセージの宛先
| |
| "org.freedesktop.login1.Manager.PowerOff" \ # D-Busインターフェース名(org.freedesktop.login1.Manager)とメソッド名(PowerOff)
| |
| boolean:true # メソッド名の引数 (引数の型(boolean)と値(true))
| |
|
| |
| # 再起動
| |
| dbus-send --print-reply=literal \
| |
| --system \ # バスタイプ
| |
| --dest=org.freedesktop.login1 \ # バス名(D-Busサービス名)
| |
| /org/freedesktop/login1 \ # D-Busオブジェクト名(オブジェクトパス)
| |
| # バス名(D-Busサービス)に送信するメッセージに含まれるそのバス名(D-Busサービス)内におけるメッセージの宛先
| |
| "org.freedesktop.login1.Manager.Reboot" \ # D-Busインターフェース名(org.freedesktop.login1.Manager)とメソッド名(Reboot)
| |
| boolean:true # メソッド名の引数 (引数の型(boolean)と値(true))
| |
| <br><br>
| |
| | |
| == D-Bus向け設定ファイル ==
| |
| メッセージ・バス・デーモンは、特定のアプリケーションに特化した設定ファイルを持っている。<br>
| |
| 例えば、ある設定ファイルではメッセージバスをシステム全体のメッセージバスとして設定し、別の設定ファイルではユーザログインセッションごとのバスとして設定することができる。<br>
| |
| <br>
| |
| また、設定ファイルでは、リソースの制限やセキュリティパラメータ等も設定できる。<br>
| |
| <br>
| |
| これらの設定ファイルは、相互運用性の仕様の一部ではなく、後方互換性は保証されていないことに注意すること。<br>
| |
| <br>
| |
| 標準的なシステム全体およびセッションごとのメッセージバスの設定は、/usr/share/dbus-1/system.confファイルおよび/usr/share/dbus-1/session.confファイルで設定される。<br>
| |
| これらのファイルは、通常、/etc/dbus-1/system-local.confファイルまたはsession-local.confファイルをインクルードしている。<br>
| |
| 主な設定ファイルを変更しないように、これらのファイルにローカルなオーバーライドすることができる。<br>
| |
| <br>
| |
| 標準のシステムバスは通常、/usr/share/dbus-1/system.dディレクトリから追加のXMLファイルを読み込む。<br>
| |
| サードパーティ製のソフトウェアは、dbus 1.10 (2015年にリリース)からサポートされている正しい動作に必要なデフォルトポリシーを、そのディレクトリにインストールする必要がある。<br>
| |
| <br>
| |
| 標準のシステムバスは、通常、/etc/dbus-1/system.dディレクトリからXMLファイルも読み込むため、システム管理者がデフォルトポリシーを上書きしたい場合に使用する。<br>
| |
| <br>
| |
| <u>ただし、サードパーティ製のソフトウェアは、歴史的に、/etc/dbus-1/system.dディレクトリにXMLファイルをインストールしていたが、現在は非推奨とされており、</u><br>
| |
| /etc/dbus-1/system.dディレクトリは、システム管理者のために予約されたものとして扱われるべきである。<br>
| |
| <br><br>
| |
| | |
| == 便利なツール ==
| |
| D-Busのバスの検索やD-Busを使用したソフトウェアの開発には、いくつかのエンドユーザ向けの便利なツールが存在する。<br>
| |
| <br>
| |
| ==== qdbus ====
| |
| <code>qdbus</code>コマンドは、コマンドラインツールであり、与えられたバス上のサービス、オブジェクト、インタフェースを表示したり、バス上の与えられたアドレスにメッセージを送信するために使用できる。<br>
| |
| これは、セッションバスおよびシステムバスの両方を検索するために使用することができる。 <br>
| |
| <br>
| |
| <code>--system</code>オプションを付加する場合は、qdbusはシステムバスに接続する。<br>
| |
| <code>--system</code>オプションを付加しない場合は、セッションバスを使用する。<br>
| |
| <br>
| |
| <code>qdbus</code>コマンドは、与えられた引数を、与えられたオブジェクトに渡すためのアドレス、および、パラメータ(存在する場合)として使用する。<br>
| |
| もし、完全なアドレスが与えられなかった場合、バス上のその地点から利用可能な全てのオブジェクトを表示する。<br>
| |
| <br>
| |
| 例えば、アドレスが提供されない場合は、利用可能なサービスのリストが表示される。<br>
| |
| サービス名を指定する場合、オブジェクトのパスが提供される。<br>
| |
| パスを指定する場合、全てのインターフェースの全てのメソッドが表示される。<br>
| |
| <br>
| |
| このように、非常に簡単にバス上のオブジェクトを検索して操作することができる。<br>
| |
| <br>
| |
| ==== qdbusviewer ====
| |
| <code>qdbusviewer</code>は、Qtで作成されたGUIソフトウェアであり、<code>qdbus</code>コマンドがCUIから提供する機能と基本的に同一のものをGUIとして提供している。<br>
| |
| <code>qdbusviewer</code>は、Qt本体と同梱されており、オブジェクトアドレス等のD-Busの基本概念に慣れていれば、誰でも簡単に使用できる。<br>
| |
| <br><br> | | <br><br> |
|
| |
|