D-BUS基礎介紹


homepage

1. What is D-Bus?

D-Bus is a system for interprocess communication (IPC). Architecturally, it has several layers.

Dbus是實質上一個適用於桌面應用的進程間的通訊機制,即所謂的IPC機制——適合在同一台機器,不適合於Internet的IPC機制。

  • libdbus: 運行庫,或者稱之為協議的實現。
  • message bus daemon executable: 后台服務進程
  • bindings: 客戶端綁定,例如 libdbus-glib & libdbus-qt & dbus-python...

libdbus only supports one-to-one connections, just like a raw network socket. However, rather than sending byte streams over the connection, you send messages. Messages have a header identifying the kind of message, and a body containing a data payload. libdbus also abstracts the exact transport used (sockets vs. whatever else), and handles details such as authentication.

The message bus daemon forms the hub of a wheel. Each spoke of the wheel is a one-to-one connection to an application using libdbus. An application sends a message to the bus daemon over its spoke, and the bus daemon forwards the message to other connected applications as appropriate. Think of the daemon as a router.

The bus daemon has multiple instances on a typical computer. The first instance is a machine-global singleton(SystemBus), that is, a system daemon similar to sendmail or Apache. This instance has heavy security restrictions on what messages it will accept, and is used for systemwide communication. The other instances are created one per user login session(SessionBus). These instances allow applications in the user's session to communicate with one another.
The systemwide and per-user daemons are separate. Normal within-session IPC does not involve the systemwide message bus process and vice versa.

以下內容取自 linuxjournal.com,概括了D-Bus的功能:

D-BUS 的直接目標,就是代替(或者說是統一)GNOME中的 CORBA 與 KDE中的 DCOP 。具體包括以下層面的功能:

  1. 作為IPC,利用 UNIX domain sockets 傳輸數據
  2. 作為系統組件,傳遞信號 & 觸發事件,例如藍牙Daemon可以把藍牙耳機的按鈕廣播給Player等多個軟件。
  3. D-BUS implements a remote object system, letting one application request services and invoke methods from a different object—think CORBA without the complications.

為此,D-BUS首先實現了一整套數據通訊協議。

First, the basic unit of IPC in D-BUS is a message, not a byte stream. In this manner, D-BUS breaks up IPC into discrete messages, complete with headers (metadata) and a payload (the data). The message format is binary, typed, fully aligned and simple. It is an inherent part of the wire protocol. This approach contrasts with other IPC mechanisms where the lingua franca is a random stream of bytes, not a discrete message.

2. Why is D-Bus?

Dbus提供了一個低時延、低消耗的IPC通訊,因為它采用了二進制的數據交換協議,不需要轉換成文本化的數據進行交換。

典型的桌面都會有多個應用程序在運行,而且,它們經常需要彼此進行通信。DCOP 是一個用於 KDE 的 解決方案,但是它依賴於 Qt,所以不能用於其他桌面環境之中。類似的,Bonobo 是一個用於 GNOME 的 解決方案,但是非常笨重,因為它是基於 CORBA 的。它還依賴於 GObject,所以也不能用於 GNOME 之外。 D-BUS 的目標是將 DCOP 和 Bonobo 替換為簡單的 IPC,並集成這兩種桌面環境。由於盡可能地減少了 D-BUS 所需的依賴,所以其他可能會使用 D-BUS 的應用程序不用擔心引入過多依賴。

There are many, many technologies in the world that have "Inter-process communication" or "networking" in their stated purpose: CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE), and probably hundreds more. Each of these is tailored for particular kinds of application. D-Bus is designed for two specific cases:

  1. Communication between desktop applications in the same desktop session; to allow integration of the desktop session as a whole, and address issues of process lifecycle (when do desktop components start and stop running).

  2. Communication between the desktop session and the operating system, where the operating system would typically include the kernel and any system daemons or processes.

D-Bus may happen to be useful for purposes other than the one it was designed for. Its general properties that distinguish it from other forms of IPC are:
Binary protocol designed to be used asynchronously (similar in spirit to the X Window System protocol).

  1. Stateful, reliable connections held open over time.
  2. The message bus is a daemon, not a "swarm" or distributed architecture.
  3. Many implementation and deployment issues are specified rather than left ambiguous/configurable/pluggable.
  4. Semantics are similar to the existing DCOP system, allowing KDE to adopt it more easily.
  5. Security features to support the systemwide mode of the message bus.

2.1. 思考

  1. 對於Message bus,作為守護進程,能否稱之為MOM中間件?不能,但為什么?眾所周知,DBus源於CORBA,這個問題可以引申為:ORB與RPC或是MOM之間的本質區別是什么?畢竟這幾類產品從外觀上(作用上)看都太相似了。

    答:注意,daemon並不包括消息隊列——它只是實現了消息的轉發——這是Message Dispatcher做的事兒,但這個過程中並沒有對消息排隊、存儲。它只是在收到消息的第一時間保證消息被作為廣播,或是路由到正確的進程上去。

  2. 類似router運行的daemon,在底層上是否就是一個broker?

    答:從其結構圖上就能看出,daemon包含了一個Message Dispatcher,這個就是實現消息轉發的router

  3. 如果Dbus的機制沒有過多的依賴,且低延時、高效率,為何僅作為desktop的IPC?——它的底層用的是UNIX Domain Socket,那換成TCP/UDP不就可以聯通Internet了?

    答:實際上DBus底層的通訊實現的方式由多種,包括了UDS或是TCP/UDP,但它沒有將通訊拓展到Internet,這只能說明網絡間的通訊還存在着某個層面的復雜度——當然這個問題有待深究。

  4. SystemBus是否可以在終端中使用?如果是,SessionBus的區分僅僅是為了隔離不同Session傳遞的消息嗎?

    答:是的,Debian系統默認會運行 dbus-daemon --system ,即使系統沒有安裝桌面環境——說明SystemBus與桌面是沒有關系的,它只是完成通用的系統層面的消息傳遞。所以,用戶完全可以在終端下創建和調用SystemBus對象並進行操作。

3. D-BUS Concepts(核心概念)

消息由消息頭和消息體組成。消息頭由消息的固有字段信息組成。消息體由一串字符串值組成。消息體的每個字符串值的意義由消息頭中的描述指定,消息頭的長度必須是8的倍數,相應的,消息體由8的倍數處開始。

Objects are addressed using path names, such as /org/cups/printers/queue . Processes on the message bus are associated with objects and implemented interfaces on that object.

3.1. Messages, 消息

在 D-BUS 中有四種類型的消息:

方法調用(method calls):觸發對象的一個方法
方法返回(method returns):返回觸發后的結果
信號(signals):通知,可以看作事件消息
錯誤(errors):返回觸發的錯誤信息

3.2. Service Name, 服務名稱

當通過總線進行通信時,應用程序會獲得“服務名稱”:應用程序可以選擇以什么樣的方式被同一個總線上的其他應用程序所知道。

服務名稱由D-Bus的守護進程代理,被用來將消息從一個app發送到另一個app。“服務名稱”的類似概念是IP地址和hostname主機名。

另一方面,如果總線沒有在使用,則“服務名稱”也不會被使用。這等同於“點對點”網絡:由於對側是已知的,就沒有必要使用IP地址或者主機名了。

“服務名稱”的格式與主機名類似。例如D-Bus服務由http://freedesktop.org定義,可以在總線上根據“org.freedesktop.DBus”這個“服務名稱”來找到D-Bus服務。

一個應用連接到bus daemon會分配一個名字給這個連接。這個唯一標識的名字以冒號 : 開頭(例如“:34-907”)。但是這種名字總是臨時分配,無法確定的,也難以記憶,因此應用可以要求有另外一個名字well-known name 來對應這個唯一標識,就像我們使用域名來對應IP地址一樣。例如可以使用 com.mycompany 來映射 :34-907

3.3. Object path, 對象路徑

app通過導出對象來向其他app提供特定服務。這些對象是分層組織的,就像從QObject派生的類具有父子關系一樣。但有一點不同,就是存在“根對象”概念,即所有的對象都有最終的父對象。

如果我們還是和Web服務對比,對象路徑等同於URL地址部分:/pub/something。必須以斜線開始!

3.4. Interface, 接口

接口概念類似於C++的抽象類,聲明了“契約”。也就是說它們建立了方法、信號、屬性的名字。Qt的插件系統也使用了類似的機制:C++的基類通過Q_DECLARE_INTERFACE()來識別唯一的標識符。事實上,D-Bus接口名稱的命名方式類似於Qt插件系統提供的方式:通常由定義該接口的實體的域名構建的標識符。


Big Conceptual Picture : Address -> [Bus Name] -> Path -> Interface -> Method

bus name是可選的,除非是希望把消息送到特定的應用中才需要。interface也是可選的,有一些歷史原因,DCOP不需要指定接口,因為DCOP在同一個對象中禁止同名的方法。

D-BUS is fully typed and type-safe. Both a message's header and payload are fully typed. Valid types include byte, Boolean, 32-bit integer, 32-bit unsigned integer, 64-bit integer, 64-bit unsigned integer, double-precision floating point and string. A special array type allows for the grouping of types. A DICT type allows for dictionary-style key/value pairs.

D-BUS is secure. It implements a simple protocol based on SASL profiles for authenticating one-to-one connections. On a bus-wide level, the reading of and the writing to messages from a specific interface are controlled by a security system. An administrator can control access to any interface on the bus. The D-BUS daemon was written from the ground up with security in mind.

注:以上是一些精簡的概念說明,但非常到位。如果想得到更詳細的說明,參考官網:https://www.freedesktop.org/wiki/IntroductionToDBus/

對比前后兩張d-feet截圖,可以看到 address 可以共用(一個 UNIX Domain Socket 連接中傳遞了多個Bus Object的信息),Bus Name 可以重復,Unique Name 則不能重復。因此對象是由(BusName + ObjectPath)唯一確定的。注意:通信雙方是Object,不是application。

在一個Object中,可以包括多個Interface——可以理解為對功能的分組(或者說是Namespace),是多個方法和信號的集合。

4. Tools

  • 要查看Dbus總線上的服務和對象可以借助 d-feetqdbusviewer
  • 要發送信號可以使用 dbus-send
  • 要查看Dbus上的消息流可以使用 dbus-monitor
  • 環境變量 DBUS_SESSION_BUS_ADDRESS 的值即為dbus-daemon的總線地址

5. 協議淺析

5.1. 數據類型

Signature Strings

D-Bus uses a string-based type encoding mechanism called Signatures to describe the number and types of arguments requried by methods and signals. Signatures are used for interface declaration/documentation, data marshalling, and validity checking. Their string encoding uses a simple, though expressive, format and a basic understanding of it is required for effective D-Bus use. The table below lists the fundamental types and their encoding characters.

Container TypesNo spacing is allowed within signature strings. When defining signatures for multi-argument methods and signatures, the types of each argument are concatenated into a single string. For example, the signature for a method that accepts two integers followed by a string would be "iis".

There are four container types: Structs, Arrays, Variants, and Dictionaries.

Structs

Structures are enclosed by parentheses and may contain any valid D-Bus signature. For example, (ii) defines a structure containing two integers and ((ii)s) defines a structure containing a structure of two integers followed by a string. Empty structures are not permitted.

Arrays

Arrays define a list consisting of members with a fixed type. The array charater a must be immediately followed by the type of data in the array. This must be a single, complete type.

Examples

  • ai - Array of 32-bit integers
  • a(ii) - Array of structures
  • aai - Array of array of integers

Variants

Variants may contain a value of any type. The marshalled value of the variant includes the D-Bus signature defining the type of data it contains.

Dictionaries

Dictionaries work in a manner similar to that of structures but are restricted to arrays of key = value pairs. The key must be a basic, non-container type and the value may be any single, complete type. Dictionaries are defined in terms of arrays using {} to surround the key and value types. Examples:

  • a{ss} - string ⇒ string
  • a{is} - 32-bit signed integer ⇒ string
  • a{s(ii)} - string ⇒ structure containing two integers
  • a{sa{ss}} - string ⇒ dictionary of string to string

5.2. 消息路由

Messages are routed to client connections by destination address and match rules. Destination address routing is used when a message’s destination parameter contains a unique or well-known bus name. This is typically the case with method call and return messages which inherently require 1-to-1 communication. Signals, on the other hand, are broadcast messages with no specific destination. For these, client applications must register match rules in order to receive the signals they are interested in.

Although signal registration is the most common use for message matching rules, DBus message matching rules can be used to request delivery of any messages transmitted over the bus; including the method call and return messages between arbitrary bus clients. The messages delivered via match rules are always copies so it is not possible to use this mechanism to redirect messages away from their intended targets.

Message match rules are set via the org.freedesktop.DBus.AddMatch method and are formatted as a series of comma-separated, key=value paris contained within a single string. Excluded keys indicate wildcard matches that match every message. If all components of the match rule match a message, it will be delivered to the requesting application. The following table provides a terse description of the keys and values that may be specified in match rules. For full details, please refer to the DBus specification.

5.3. 標准功能接口

For example:

6. How to use(原理)

homepage

6.1. Message

D-Bus works by sending messages between processes. If you're using a sufficiently high-level binding, you may never work with messages directly.There are 4 message types:

  • Method call messages ask to invoke a method on an object.
  • Method return messages return the results of invoking a method.
  • Error messages return an exception caused by invoking a method.
  • Signal messages are notifications that a given signal has been emitted (that an event has occurred). You could also think of these as "event" messages.

A method call maps very simply to messages: you send a method call message, and receive either a method return message or an error message in reply.Each message has a header, including fields, and a body, including arguments. You can think of the header as the routing information for the message, and the body as the payload. Header fields might include the sender bus name, destination bus name, method or signal name, and so forth. One of the header fields is a type signature describing the values found in the body. For example, the letter "i" means "32-bit integer" so the signature "ii" means the payload has two 32-bit integers.

6.2. Calling a Method

A method call in DBus consists of two messages; a method call message sent from process A to process B, and a matching method reply message sent from process B to process A. Both the call and the reply messages are routed through the bus daemon. The caller includes a different serial number in each call message, and the reply message includes this number to allow the caller to match replies to calls.

The call message will contain any arguments to the method. The reply message may indicate an error, or may contain data returned by the method.

A method invocation in DBus happens as follows:

  1. The language binding may provide a proxy, such that invoking a method on an in-process object invokes a method on a remote object in another process. If so, the application calls a method on the proxy, and the proxy constructs a method call message to send to the remote process.
  2. For more low-level APIs, the application may construct a method call message itself, without using a proxy.
  3. In either case, the method call message contains: a bus name belonging to the remote process; the name of the method; the arguments to the method; an object path inside the remote process; and optionally the name of the interface that specifies the method.
  4. The method call message is sent to the bus daemon.
  5. The bus daemon looks at the destination bus name. If a process owns that name, the bus daemon forwards the method call to that process. Otherwise, the bus daemon creates an error message and sends it back as the reply to the method call message.
  6. The receiving process unpacks the method call message. In a simple low-level API situation, it may immediately run the method and send a method reply message to the bus daemon. When using a high-level binding API, the binding might examine the object path, interface, and method name, and convert the method call message into an invocation of a method on a native object (GObject, java.lang.Object, QObject, etc.), then convert the return value from the native method into a method reply message.
  7. The bus daemon receives the method reply message and sends it to the process that made the method call.
  8. The process that made the method call looks at the method reply and makes use of any return values included in the reply. The reply may also indicate that an error occurred. When using a binding, the method reply message may be converted into the return value of of a proxy method, or into an exception.

The bus daemon never reorders messages. That is, if you send two method call messages to the same recipient, they will be received in the order they were sent. The recipient is not required to reply to the calls in order, however; for example, it may process each method call in a separate thread, and return reply messages in an undefined order depending on when the threads complete. Method calls have a unique serial number used by the method caller to match reply messages to call messages.

6.3. Emitting a Signal

A signal in DBus consists of a single message, sent by one process to any number of other processes. That is, a signal is a unidirectional broadcast. The signal may contain arguments (a data payload), but because it is a broadcast, it never has a "return value." Contrast this with a method call (see the section called “Calling a Method - Behind the Scenes”) where the method call message has a matching method reply message.

The emitter (aka sender) of a signal has no knowledge of the signal recipients. Recipients register with the bus daemon to receive signals based on "match rules" - these rules would typically include the sender and the signal name. The bus daemon sends each signal only to recipients who have expressed interest in that signal.

A signal in DBus happens as follows:

  1. A signal message is created and sent to the bus daemon. When using the low-level API this may be done manually, with certain bindings it may be done for you by the binding when a native object emits a native signal or event.
  2. The signal message contains the name of the interface that specifies the signal; the name of the signal; the bus name of the process sending the signal; and any arguments
  3. Any process on the message bus can register "match rules" indicating which signals it is interested in. The bus has a list of registered match rules.
  4. The bus daemon examines the signal and determines which processes are interested in it. It sends the signal message to these processes.
  5. Each process receiving the signal decides what to do with it; if using a binding, the binding may choose to emit a native signal on a proxy object. If using the low-level API, the process may just look at the signal sender and name and decide what to do based on that.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM