• D-BUS详细分析

    2017-04-14 19:25:37
    一、概述  官方网站:http://www.freedesktop.org/wiki/Software/dbus,但是如果要下...可以从svn上拿,具体见后面的dbus编译部分。  从官方首页中可以看到这样一段描述D-BUS 的话:“D-Bus is a message b
    
    

    一、概述

          官方网站:http://www.freedesktop.org/wiki/Software/dbus,但是如果要下windows版的代码最好不要从sourceforge下,多次下来的1.2.4版本都无法正常解压。可以从svn上拿,具体见后面的dbus编译部分。

          从官方首页中可以看到这样一段描述D-BUS 的话:“D-Bus is a message bus system, a simple way for applications to talk to one another. In addition to interprocess communication, D-Bus helps coordinate process lifecycle; it makes it simple and reliable to code a "single instance" application or daemon, and to launch applications and daemons on demand when their services are needed. ”

          因此,D-BUS从本质来说就是进程间通信(inter-process communication)(IPC)的一个实现。他最初产生于Linux平台,是做为freedesktop.org项目的一部分来开发的。正开始深入地渗透到 Linux 桌面之中。已经在Qt4,GNOME,Windows以及Maemo实现。在KDE4中已经取代了著名的DCOP,在GNOME取代笨重的Bonobo。在嵌入式系统中常用来实现C/S结构。

    作为一个IPC,他实现了两点:

          1.在同一个桌面会话中不同的应用程序进行通讯:系统总线(system bus),这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序不能欺骗系统事件。应用程序可以直接和系统总线通信,但是发送的消息受限制。

            2.桌面程序与内核或守护进程进行通讯:会话总线(Session bus),属于登录用户私有。它是用户的应用程序用来通信的一个会话总线。

    二、D-BUS 特性

         1.D-BUS的协议是低延迟而且低开销的,设计得小(但是代码量不算很少吧)而且高效,以便最小化传送时间。从设计上避免往返交互并允许异步操作。

         2.协议是二进制的,而不是文本,这样就排除了费事的序列化过程(我们的万能参数序列化就比较占时间)。

         3.考虑了字节顺序问题。

         4.易用性:它按照消息而不是字节流来工作,并且自动地处理了许多困难的IPC问题,并且D-Bus库以可以封装的方式来设计,这样开发者就可以使用框架里存在的对象/类型系统,而不用学习一种新的专用于IPC的对象/类型系统。

         5.请求时启动服务以及安全策略。

         6.因为是做为freedesktop.org项目来开发的,有许多达人参加,所以质量应该是很有保证的。

         7.支持多语言(C/C++/Java/C Sharp/Python/Ruby),多平台(Linux/windows/maemo)。

         8.采用C语言,而不是C++。

         9.由于基本上不用于internet上的IPC,因此对本地IPC进行了特别优化。

         10.提供服务注册,理论上可以进行无限扩展。

        三、构架

          分成三层:

                    a.libdbus库,实现了底层的API以及协议,他除了需要XML解析器以外没有必须的依赖。对于不同的语言,协议可能被重新实现。这个库是一个基础,虽然官方说他不是设计给应用程序调用的,但是实际上应用程序是可以直接调用的,特别是windows版,后面的使用分析中的例子就能看到;

                    b.消息守护进程,建立在libdbus的基础上,可以管理多个应用程序之间的通信。每个应用程序都和消息守护进程建立dbus链接,由消息守护进程统一进行消息的派发;

                    c.各种包装库,绑定了一些常见的框架(qt,Glib,Java,Python,C sharp etc.)没什么新功能,只是对dbus进行了一层封装。方便使用官方建议应用程序使用这层进行调用;

    体系结构图(来自网络)

    D-BUS分析—1 介绍 - yolcy - yolcy的博客

          一、名词解释

    1. 消息 

            消息由头部和消息体组成,如果你把消息当作一个package,那头部就是地址,消息体就是包的内容。消息发送系统使用头部的信息来知道把消息送往何处,如何解释消息,接收者则解释消息体。消息体可以没有或有多个参数,这些参数是具有类型的值,如integer或byte数组。消息头和消息体都使用相同类型的type系统及格式来序列化数据。每种值的类型都有wire格式,从某种别的表示把值转换为wire格式叫作列集(marshalling),而把wire格式转回去则叫散集(unmarshalling).消息头部是有固定签名和意义的值块。消息体是另外的值块,带有在头部中指定的签名。头部必须字节对齐,这样当在一个缓冲区中存贮整个消息时可以允许消息体以8对齐开始。如果头部不是自然地终止于8字节边界上,则必须加上最多7字节的nul初始化的对齐填充。消息体不需要字节对齐。消息的最大长度,包括头,头对齐填充以及消息体是2的27次幂即134217728。实现不能发送或接收超过此大小的消息。头部的签名是: "yyyyuua(yv)",以更为可读的方式写出是:

      BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
      含义(摘自D-BUS spec:http://dbus.freedesktop.org/doc/dbus-specification.html):
      Value Description
      1st BYTE Endianness flag; ASCII 'l' for little-endian or ASCII 'B' for big-endian. Both header and body are in this endianness.
      2nd BYTE Message type. Unknown types must be ignored. Currently-defined types are described below.
      3rd BYTE Bitwise OR of flags. Unknown flags must be ignored. Currently-defined flags are described below.
      4th BYTE Major protocol version of the sending application. If the major protocol version of the receiving application does not match, the applications will not be able to communicate and the D-Bus connection must be disconnected. The major protocol version for this version of the specification is 1.
      1st UINT32 Length in bytes of the message body, starting from the end of the header. The header ends after its alignment padding to an 8-boundary.
      2nd UINT32 The serial of this message, used as a cookie by the sender to identify the reply corresponding to this request.
      ARRAY ofSTRUCT of (BYTE,VARIANT) An array of zero or more header fields where the byte is the field code, and the variant is the field value. The message type determines which fields are required.

      在消息头尾部的数组包含了头部域。

      消息有四种类型:METHOD_CALLMETHOD_RETURNERROR, and SIGNAL

         a.METHOD_CALL(方法调用消息)

            这类消息会调用远程对象的操作,这些消息需要映射到对象的方法上去。方法调用消息需要有MEMBER头部域用以指明方法的名称,此消息还可能有一个INTERFACE域来给出接口,被调用的方法也是接口的一部分。在没有INTERFACE域时,如果同一对象上的两个接口有同名的方法名字,哪一个方法会被调用是没有定义的。在这种具有二义性的环境里,实现可以选择返回一个错误。但是,如果方法名是独一无二的,实现不能强制要求需要interface域。还包括一个PATH域,该域用以指明在哪个对象上调用该方法。如果此调用正在消息总线中传播,消息也有一个DESTINATION域用以给出接收此消息的连接名称。当应用程序处理方法调用消息时,它需要答复,答复由REPLY_SERIAL头部域确定 ,此头部域也表明了被答复的方法调用的序列号。答复类型有两种,METHOD_RETURN和ERROR。

         b.METHOD_RETURN & ERROR

            答复消息的参数就是方法调用的返回值或"out parameters",如果答复类型为ERROR,那么会抛出例外,方法调用失败,此时没有返回值提供。对于同一个方法调用发送多个答复是没有意义的。 即使一个方法调用没有返回值,一个METHOD_RETURN的答复也是必须的,这样调用者就能知道方法是否被成功地处理了。

      METHOD_RETURN 和 ERROR答复消息必须有REPLY_SERIAL头部域。 

         d.SIGNAL

                信号发射不象方法调用需要答复。信号发射只是简单单一信息类型SIGNAL。它必须有三个头域,PATH给出发送信号的对象,加上INTERFACE和MEMBER给出信号的全称名字。INTERFACE头部域在信号中是必须的,尽管它在方法调用中是可选的。

    2. Bus Name 
      可以说是连接的名字,一个连接只有一个总线名字并且是惟一的,在此连接的整个生命周期,这个名字不变。总线名字是STRING类型的,意味着它必须是有效的UTF-8字符串。有两种作用不同的Bus Name,一个叫公共名(well-known names),还有一个叫唯一名(Unique Connection Name)。
    3. 对象 
      对象是处理消息的一个实例。对象有一个或多个接口,在每个接口有一个或多个的方法,每个方法实现了具体的消息处理。在一对一的通讯中,对象通过一个连接直接和另一个客户端应用程序连接起来。在多对多的通讯中,对象通过一个连接和Dbus守护进程连接起来。对象有一个路径用于指明该对象的存放位置,消息传递时通过该路径找到该对象。
    4. 接口 
      每个对象都有一个或者多个接口,一个接口就是多个方法和信号的集合。dbus使用简单的命名空间字符串来表示接口,如org.freedesktop.Introspectable。可以说dbus接口相当于C++中的纯虚类。
    5. 方发和信号 
      每个对象都有一些成员,两种成员:方法(methods)和信号(signals),在对象中,方法可以被调用。信号会被广播,感兴趣的对象可以处理这个信号,同时信号中也可以带有相关的数据。每一个方法或者信号都可以用一个名字来命名,如”Frobate” 或者 “OnClicked”。
    6. 对象路径 
      一个对象路径是一个用于引用对象实例的名字,从概念上讲,D-Bus信息交换中每个参与者可能有任意数量的对象实例并且每个这样的实例都有一个路径,就象文件系统一样,一个应用中的对象实例形成一个层次树。
    7. 服务 
      服务是 D-BUS 的最高层次抽象,它们的实现当前还在不断发展变化。应用程序可以通过一个总线来注册一个服务,如果成功,则应用程序就已经 获得 了那个服务。其他应用程序可以检查在总线上是否已经存在一个特定的服务,如果没有可以要求总线启动它。
    8. dbus-daemon 
      dbus的后台程序(守护进程),libdbus运行时会自动创建dbus-daemon进程。daemon就像一个路由器,将从发送者连接得到的消息转发到由消息中的接收者连接名指定的接收者连接中。
    9. 连接 
      连接是一个双向的消息传递通道。一个连接将对象和Dbus(dubs-daemon)或客户端应用连接起来,连接支持非阻塞式的异步消息发送和阻塞式的同步消息发送。消息通过连接到达目的端后,连接会将挂起在该连接上的进程唤醒,由该进程将消息取走。每个连接都有一个唯一的名字和可选的其他多个名字,用于在多对多通讯时指明消息的发送者和接收者
    10. 认证协议(Authentication Protocol)

      消息流开始之前,两个应用之间必须进行认证,简单的纯文本协议用来认证,即SASL档案,相当简单地直接从SASL规范映射过来。没有使用消息编码,只是纯文本信息。

          二、运行机制

           客户端应用是请求消息的发起者。客户端应用通过和自身的相连的一个连接将请求消息发送出去,也通过该连接接收回应的消息、错误消息、系统更新消息等。在一对一的通讯中,请求消息直接到达对象。在多对多的通讯中,请求消息先到达Dbus,Dbus将消息转发到目的对象。每个连接使用bus name来标识的,bus name有两种,一种是公共名(well-known Name),一种是唯一名(Unique Connection Name)。

          所有使用D-BUS的应用程序都包含一些对象,它们一般映射为GObject、QObject、C++对象、或者[[Python">Python</a>对象。当经由一个D-BUS连接收到一条消息时,该消息是被发往一个对象而不是整个应用程序。这一点和我们常见的消息机制是不太一样的。这个对象其实很像C++中虚函数

          为了允许消息能指定接收对象,还要提供引用对象的方法。但是这个引用一般实现为与应用程序相关的内存地址,因此无法在应用程序之间传递。为了解决这一问题,D-BUS为每个对象引入名字。这些名字看起来像是文件系统路径,例如一个对象可能叫做 “/org/kde/kspread/sheets/3/cells/4/5”。路径名以容易阅读为佳,没有具体的硬性规定。

    在dbus中调用一个方法包含了两条消息,进程A向进程B发送方法调用消息,进程B向进程A发送应答消息。所有的消息都由daemon进行分派,每个调用的消息都有一个不同的序列号,返回消息包含这个序列号,以方便调用者匹配调用消息与应答消息。调用消息包含一些参数,应答消息可能包含错误标识,或者包含方法的返回数据。

            1.方法调用的一般流程: 
    a.使用不同语言绑定的dbus高层接口,都提供了一些代理对象,调用其他进程里面的远端对象就像是在本地进程中的调用一样。应用调用代理上的方法,代理将构造一个方法调用消息给远端的进程。 
    b.在DBUS的底层接口中,应用需要自己构造方法调用消息(method call message),而不能使用代理。 
    c.方法调用消息里面的内容有:目的进程的bus name,方法的名字,方法的参数,目的进程的对象路径,以及可选的接口名称。 
    d.方法调用消息是发送到bus daemon中的。 
    e.bus daemon查找目标的bus name,如果找到,就把这个方法发送到该进程中,否则,daemon会产生错误消息,作为应答消息给发送进程。 
    f.目标进程解开消息,在dbus底层接口中,会立即调用方法,然后发送方法的应答消息给daemon。在dbus高层接口中,会先检测对象路径,接口,方法名称,然后把它转换成对应的对象(如GObject,QT中的QObject等)的方法,然后再将应答结果转换成应答消息发给daemon。 
    g.bus daemon接受到应答消息,将把应答消息直接发给发出调用消息的进程。 
    h.应答消息中可以包容很多返回值,也可以标识一个错误发生,当使用绑定时,应答消息将转换为代理对象的返回值,或者进入异常。

    bus daemon不对消息重新排序,如果发送了两条消息到同一个进程,他们将按照发送顺序接受到。接受进程并需要按照顺序发出应答消息,例如在多线程中处理这些消息,应答消息的发出是没有顺序的。消息都有一个序列号可以与应答消息进行配对。

     

    在dbus中一个信号包含一条信号消息,一个进程发给多个进程。也就是说,信号是单向的广播。信号可以包含一些参数,但是作为广播,它是没有返回值的。

    信号触发者是不了解信号接受者的,接受者向daemon注册感兴趣的信号,注册规则是”match rules”,记录触发者名字和信号名字。daemon只向注册了这个信号的进程发送信号。

           2.信号的一般流程如下: 
    a.当使用dbus底层接口时,信号需要应用自己创建和发送到daemon,使用dbus高层接口时,可以使用相关对象进行发送,如Glib里面提供的信号触发机制。 
    b.信号包含的内容有:信号的接口名称,信号名称,发送进程的bus name,以及其他参数。 
    c.任何进程都可以依据”match rules”注册相关的信号,daemon有一张注册的列表。 
    d.daemon检测信号,决定哪些进程对这个信号感兴趣,然后把信号发送给这些进程。 
    e.每个进程收到信号后,如果是使用了dbus高层接口,可以选择触发代理对象上的信号。如果是dbus底层接口,需要检查发送者名称和信号名称,然后决定怎么做。

         三、将消息调用映射为本地API

          D-Bus的API可以把方法调用映射为特定编程语言(如C++)中的方法调用,或者把IDL中的方法调用映射为D-Bus消息。

    在这些方法调用中,方法的参数被标为"in"(指明是METHOD_CALL传入参数)或者"out"(指明是METHOD_CALL的传出参数),象CORBA的一些API具有"inout"参数,它表明该参数既传入又传出,即调用者传入的值将会被修改。映射到D-Bus上,"inout"参数等价于"in"参数后跟着一个"out"参数,你不能在总线上传引用,所以"inout"参数完全是幻想。如果一个方法具有0个或一个返回值,后跟着0个或多个参数,这里的每个参数可能是"in", "out"或"inout",调用者通过按顺序加上"in"或者"inout"参数来构造消息。"out"参数不会出现在调用者的消息里。接收者构造出答复,如果有返回值,则把第一个返回加到答复上,然后按顺序加上每个"out"或"inout"参数,"in"参数不会出现在答复消息里。如果使用的语言中有例外错误答复消息正常情况下被映射为例外。在转换本地API到D-Bus的API时,把D-Bus命名规范("FooBar")自动地映射到本地命名规范(fooBar/foo_bar)或许好一些。只要本地API是专门写给D-Bus就行。这样当写一个对象实现且此实现将被导出到总线上是最好的了。对象代理用于调用远程D-Bus对象,而远程D-Bus对象可能需要可以调用任何D-Bus方法的能力,因此像这样魔术般的名字映射可能是个问题。

    我们了解了什么是D-BUS了也了解了他的基本原理。精彩的是D-BUS是一个完全的opensource软件。那么是时候来看看代码了

    由于dbus是支持快平台的,自然需要先考虑清楚我们想研究的目标平台。下载了linux版和windows版,其他版本没有下。

    工作环境是windows,但是最初从官方网页指引的地方下载了一个windbus,没编译过去,本来也是一般linux的东西在Windows下编译总是一件痛苦的事情,要么借助其他第三方工具库,要么连代码都不一样。如果需要把linux porting到windows有时候也是蛮麻烦的事情,比如汇编,但是还有很多纯粹的体力劳动,比如编译器支持的语法不一样。为了能正常编译linux版偶还特意装了一个redhat 9的虚拟机。配置就搞了半天,原因很可笑,仅仅是因为安装好vmware新增的网卡是默认使用静态IP的。很多公司都是不允许的。以前怎么一点印象都没有。下载了1.2.4版本,但是在linux下编译没成功,正在找原因的时候发现可以通过svn下载windbus(dbus的windows版)代码。找了一篇编译日志,稍加整理hoho编译、运行一切ok。下面是整理出来的编译dbus Windows版的步骤:

    1.下载代码

    通过TortoiseSVN:

    https://windbus.svn.sourceforge.net/svnroot/windbus

    2.下载并安装cmake

    http://www.cmake.org/files/v2.6/cmake-2.6.1-win32-x86.exe,安装到<ProgramDir>\gnuwin32 
    3.下载并安装编译库

    http://www.winkde.org/pub/kde/ports/win32/releases/stable/4.1.1/libxml2-2.6.32-1-lib.tar.bz2

    http://www.winkde.org/pub/kde/ports/win32/releases/stable/4.1.1/libxml2-2.6.32-1-bin.tar.bz2

    http://www.winkde.org/pub/kde/ports/win32/releases/stable/4.1.1/expat-2.0.1-bin.zip

    http://www.winkde.org/pub/kde/ports/win32/releases/stable/4.1.1/expat-2.0.1-lib.zip

    将以上库都解压至<ProgramDir>\gnuwin32目录,把四个库里所有lib,bin目录下的文件都拷贝到<ProgramDir>\gnuwin32目录下的bin和lib目录 
    3.使用cmake生成sln文件

       a.将windbus\tags\1.2.4拷到一个新的目录如:C:\winbus-1.2.4\source

       b.创建一个新的目录,用于生成sln文件以及其他需要的相关文件和目录。如:C:\winbus-1.2.4\compile

       c.打开CMD,进入到C:\windbus-1.2.4\complile目录,执行cmake -G "Visual Studio 8 2005" ..\windbus-1.2.4\source\cmake

       d.如果成功,complie目录下将生成sln文件,VS2005打开此文件即可进行编译。

    注意:VS2008 用cmake -G "Visual Studio 9 2008" ..\windbus-1.2.4\source\cmake 命令,其他版本请参见cmakehelp

    展开全文
  • Linux D-BUS

    2009-07-06 15:49:00
    What is D-Bus?D-Bus is a system for interprocess communication (IPC). Architecturally, it has several layers: A library, libdbus, that allows two applications to connect to each

    What is D-Bus?

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

    • A library, libdbus, that allows two applications to connect to each other and exchange messages.

    • A message bus daemon executable, built on libdbus, that multiple applications can connect to. The daemon can route messages from one application to zero or more other applications.

    • Wrapper libraries or bindings based on particular application frameworks. For example, libdbus-glib and libdbus-qt. There are also bindings to languages such as Python. These wrapper libraries are the API most people should use, as they simplify the details of D-Bus programming. libdbus is intended to be a low-level backend for the higher level bindings. Much of the libdbus API is only useful for binding implementation.

     

    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, 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. 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.

     

    来源:dbus.freedesktop.org/doc/dbus-tutorial.html

    展开全文
  • D-Bus 体系

    2009-12-24 11:28:00
    有很多种IPC或者网络通信系统,如:CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE)等等,可能会有数百种,dbus的目的主要是下面两点:1.在同一个桌面会话中,进行桌面应用程序...

    有很多种IPC或者网络通信系统,如:CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE)等等,可能会有数百种,dbus的目的主要是下面两点:
    1.在同一个桌面会话中,进行桌面应用程序之间的通讯
    2.桌面程序与内核或者守护进程的通信。

    Dbus是一套进程通信体系,它有以下几层:
    1.libdbus库,提供给各个应用程序调用,使应用程序具有通信和数据交换的能力,两个应用程序可以直接进行通信,就像是一条socket通道,两个程序之间建立通道之后,就可以通讯了。
    2.消息守护进程,在libdbus的基础上创建,可以管理多个应用程序之间的通信。每个应用程序都和消息守护进程建立dbus的链接,然后由消息守护进程进行消息的分派。
    3.各种包装库,有libdbus-glib,libdbus-qt等等,目的是将dbus的底层api进行一下封装。

    下面有一张图可以很方便说明dbus的体系结构。
    dbus

    dbus中的消息由一个消息头(标识是哪一种消息)和消息数据组成,比socket的流式数据更方便一些。bus daemon 就像是一个路由器,与各个应用程序进行连接,分派这些消息。bus daemon 在一台机器上有多个实例,第一个实例是全局的实例,类似于sendmail和或者apache,这个实例有很严格的安全限制,只接受一些特定的系统消息,用于系统通信。其他bus daemon是一些会话,用于用户登录之后,在当前会话(session)中进行的通讯。系统的bus daemon 和会话的bus daemon 是分开的,彼此不会互相影响,会话bus daemon 不会去调用系统的bus daemon 。

    Native Objects and Object Paths
    在不同的编程语言中,都定义了一些“对象”,如java中的java.lang.Object,GLIB中的GObject,QT中的QObject等等。D-BUS的底层接口,和libdbus API相关,是没有这些对象的概念的,它提供的是一种叫对象路径(object path),用于让高层接口绑定到各个对象中去,允许远端应用程序指向它们。object path就像是一个文件路径,可以叫做/org/kde/kspread/sheets/3/cells/4/5等。

    Methods and Signals
    每个对象都有一些成员,两种成员:方法(methods)和信号(signals),在对象中,方法可以被调用。信号会被广播,感兴趣的对象可以处理这个信号,同时信号中也可以带有相关的数据。每一个方法或者信号都可以用一个名字来命名,如”Frobate” 或者 “OnClicked”。

    Interfaces
    每个对象都有一个或者多个接口,一个接口就是多个方法和信号的集合。dbus使用简单的命名空间字符串来表示接口,如org.freedesktop.Introspectable。可以说dbus接口相当于C++中的纯虚类。

    Proxies
    代理对象用于模拟在另外的进程中的远端对象,代理对象像是一个正常的普通对象。d-bus的底层接口必须手动创建方法调用的消息,然后发送,同时必须手动接受和处理返回的消息。高层接口可以使用代理来替换这些,当调用代理对象的方法时,代理内部会转换成dbus的方法调用,等待消息返回,对返回结果解包,返回给相应的方法。可以看看下面的例子,使用dbus底层接口编写的代码:
    Message message = new Message("/remote/object/path", "MethodName", arg1, arg2);
    Connection connection = getBusConnection();
    connection.send(message);
    Message reply = connection.waitForReply(message);
    if (reply.isError()) {

    } else {
    Object returnValue = reply.getReturnValue();
    }

    使用代理对象编写的代码:
    Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path");
    Object returnValue = proxy.MethodName(arg1, arg2);

    客户端代码减少很多。

     

    Bus Names
    当一个应用程序连接上bus daemon时,daemon会分配一个唯一的名字给它。以冒号(:)开始,这些名字在daemon的生命周期中是不会改变的,可以认为这些名字就是一个IP地址。当这个名字映射到应用程序的连接上时,应用程序可以说拥有这个名字。同时应用可以声明额外的容易理解的名字,比如可以取一个名字com.mycompany.TextEditor,可以认为这些名字就是一个域名。其他应用程序可以往这个名字发送消息,执行各种方法。

    名字还有第二个重要的用途,可以用于跟踪应用程序的生命周期。当应用退出(或者崩溃)时,与bus的连接将被OS内核关掉,bus将会发送通知,告诉剩余的应用程序,该程序已经丢失了它的名字。名字还可以检测应用是否已经启动,这往往用于只能启动一个实例的应用。

    Addresses
    使用d-bus的应用程序既可以是server也可以是client,server监听到来的连接,client连接到server,一旦连接建立,消息就可以流转。如果使用dbus daemon,所有的应用程序都是client,daemon监听所有的连接,应用程序初始化连接到daemon。

    dbus地址指明server将要监听的地方,client将要连接的地方,例如,地址:unix:path=/tmp/abcdef表明server将在/tmp/abcdef路径下监听unix域的socket,client也将连接到这个socket。一个地址也可以指明是TCP/IP的socket,或者是其他的。

    当使用bus daemon时,libdbus会从环境变量中(DBUS_SESSION_BUS_ADDRESS)自动认识“会话daemon”的地址。如果是系统daemon,它会检查指定的socket路径获得地址,也可以使用环境变量(DBUS_SESSION_BUS_ADDRESS)进行设定。

    当dbus中不使用daemon时,需要定义哪一个应用是server,哪一个应用是client,同时要指明server的地址,这不是很通常的做法。

    Big Conceptual Picture
    要在指定的对象中调用指定的方法,需要知道的参数如下:
    Address -> [Bus Name] -> Path -> Interface -> Method
    bus name是可选的,除非是希望把消息送到特定的应用中才需要。interface也是可选的,有一些历史原因,DCOP不需要指定接口,因为DCOP在同一个对象中禁止同名的方法。

    Messages - Behind the Scenes
    如果使用dbus的高层接口,就可以不用直接操作这些消息。DBUS有四种类型的消息:
    1.方法调用(method call) 在对象上执行一个方法
    2.方法返回(method return)返回方法执行的结果
    3.错误(error)调用方法产生的异常
    4.信号(signal)通知指定的信号发生了,可以想象成“事件”。

    要执行 D-BUS 对象的方法,需要向对象发送一个方法调用消息。它将完成一些处理并返回一个方法返回消息或者错误消息。信号的不同之处在于它们不返回任何内容:既没有“信号返回”消息,也没有任何类型的错误消息。

    每个消息都有一个消息头,包含多个字段,有一个消息体,包含多个参数。可以认为消息头是消息的路由信息,消息体作为一个载体。消息头里面的字段包含发送的bus name,目标bus name,方法或者信号名字等,同时消息头里面定义的字段类型规定了消息体里面的数据格式。例如:字符“i”代表了”32-bit integer”,“ii”就代表了消息体里面有两个”32-bit integer”。

    Calling a Method - Behind the Scenes
    在dbus中调用一个方法包含了两条消息,进程A向进程B发送方法调用消息,进程B向进程A发送应答消息。所有的消息都由daemon进行分派,每个调用的消息都有一个不同的序列号,返回消息包含这个序列号,以方便调用者匹配调用消息与应答消息。调用消息包含一些参数,应答消息可能包含错误标识,或者包含方法的返回数据。

    方法调用的一般流程:
    1.使用不同语言绑定的dbus高层接口,都提供了一些代理对象,调用其他进程里面的远端对象就像是在本地进程中的调用一样。应用调用代理上的方法,代理将构造一个方法调用消息给远端的进程。
    2.在DBUS的底层接口中,应用需要自己构造方法调用消息(method call message),而不能使用代理。
    3.方法调用消息里面的内容有:目的进程的bus name,方法的名字,方法的参数,目的进程的对象路径,以及可选的接口名称。
    4.方法调用消息是发送到bus daemon中的。
    5.bus daemon查找目标的bus name,如果找到,就把这个方法发送到该进程中,否则,daemon会产生错误消息,作为应答消息给发送进程。
    6.目标进程解开消息,在dbus底层接口中,会立即调用方法,然后发送方法的应答消息给daemon。在dbus高层接口中,会先检测对象路径,接口,方法名称,然后把它转换成对应的对象(如GObject,QT中的QObject等)的方法,然后再将应答结果转换成应答消息发给daemon。
    7.bus daemon接受到应答消息,将把应答消息直接发给发出调用消息的进程。
    8.应答消息中可以包容很多返回值,也可以标识一个错误发生,当使用绑定时,应答消息将转换为代理对象的返回值,或者进入异常。

    bus daemon不对消息重新排序,如果发送了两条消息到同一个进程,他们将按照发送顺序接受到。接受进程并需要按照顺序发出应答消息,例如在多线程中处理这些消息,应答消息的发出是没有顺序的。消息都有一个序列号可以与应答消息进行配对。

    Emitting a Signal - Behind the Scenes
    在dbus中一个信号包含一条信号消息,一个进程发给多个进程。也就是说,信号是单向的广播。信号可以包含一些参数,但是作为广播,它是没有返回值的。

    信号触发者是不了解信号接受者的,接受者向daemon注册感兴趣的信号,注册规则是”match rules”,记录触发者名字和信号名字。daemon只向注册了这个信号的进程发送信号。

    信号的一般流程如下:
    1.当使用dbus底层接口时,信号需要应用自己创建和发送到daemon,使用dbus高层接口时,可以使用相关对象进行发送,如Glib里面提供的信号触发机制。
    2.信号包含的内容有:信号的接口名称,信号名称,发送进程的bus name,以及其他参数。
    3.任何进程都可以依据”match rules”注册相关的信号,daemon有一张注册的列表。
    4.daemon检测信号,决定哪些进程对这个信号感兴趣,然后把信号发送给这些进程。
    5.每个进程收到信号后,如果是使用了dbus高层接口,可以选择触发代理对象上的信号。如果是dbus底层接口,需要检查发送者名称和信号名称,然后决定怎么做。

    Glib绑定接口在"dbus/dbus-glib.h"头文件中定义。
    dbus和glib的数据类型映射如下:

    D-Bus basic typeGTypeFree functionNotes
    BYTE G_TYPE_UCHAR    
    BOOLEAN G_TYPE_BOOLEAN    
    INT16 G_TYPE_INT   Will be changed to a G_TYPE_INT16 once
    GLib has it
    UINT16 G_TYPE_UINT   Will be changed to a G_TYPE_UINT16 once
    GLib has it
    INT32 G_TYPE_INT   Will be changed to a G_TYPE_INT32 once
    GLib has it
    UINT32 G_TYPE_UINT   Will be changed to a G_TYPE_UINT32 once
    GLib has it
    INT64 G_TYPE_GINT64    
    UINT64 G_TYPE_GUINT64    
    DOUBLE G_TYPE_DOUBLE    
    STRING G_TYPE_STRING g_free  
    OBJECT_PATH DBUS_TYPE_G_PROXY g_object_unref The returned proxy does not have an interface set; use
    dbus_g_proxy_set_interface to invoke methods

    Container type mappings
    dbus数据也有包容器类型,像DBUS_TYPE_ARRAY 和 DBUS_TYPE_STRUCT,dbus的数据类型可以是嵌套的,如有一个数组,内容是字符串的数组集合。

    但是,并不是所有的类型都有普通的使用,DBUS_TYPE_STRUCT应该可以包容非基本类型的数据类型。glib绑定尝试使用比较明显的方式进行声明。

    D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
    as Array of strings G_TYPE_STRV char ** g_strfreev  
    v Generic value container G_TYPE_VALUE GValue * g_value_unset The calling conventions for values expect that method callers have
    allocated return values; see below.

    同时定义了新的数组类型集合。

    D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
    ay Array of bytes DBUS_TYPE_G_BYTE_ARRAY GArray * g_array_free  
    au Array of uint DBUS_TYPE_G_UINT_ARRAY GArray * g_array_free  
    ai Array of int DBUS_TYPE_G_INT_ARRAY GArray * g_array_free  
    ax Array of int64 DBUS_TYPE_G_INT64_ARRAY GArray * g_array_free  
    at Array of uint64 DBUS_TYPE_G_UINT64_ARRAY GArray * g_array_free  
    ad Array of double DBUS_TYPE_G_DOUBLE_ARRAY GArray * g_array_free  
    ab Array of boolean DBUS_TYPE_G_BOOLEAN_ARRAY GArray * g_array_free  

    定义了字典类型

    D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
    a{ss} Dictionary mapping strings to strings DBUS_TYPE_G_STRING_STRING_HASHTABLE GHashTable * g_hash_table_destroy  

     

     

    client端编写

    我们的程序在使用dbus的时候,首先需要连接上dbus,使用dbus_g_bus_get获得dbus连接。然后可以创建代理对象。

    需要调用方法的时候,可以有两种方式:1.同步调用,使用dbus_g_proxy_call发送方法请求到远端对象,dbus会阻塞等待远端对象的回应,输出参数里将会带有相应的回应数据,以G_TYPE_INVALID作为终止符。2.异步调用,使用dbus_g_proxy_begin_call,它将返回一个DBusGPendingCall对象,可以使用dbus_g_pending_call_set_notify连接到自己的处理函授中。

    可以使用dbus_g_proxy_add_signal 和 dbus_g_proxy_connect_signal来连接信号,dbus_g_proxy_add_signal用来声明信号处理函数,属于必须被调用的接口,dbus_g_proxy_connect_signal可以调用多次。

    Generated Bindings
    使用内置的xml文件,可以很方便地自动创建出易于使用的dbus代理对象。如下的一个xml文件描述了了一个方法:


    <?xml version="1.0" encoding="UTF-8" ?>
    <node name="/com/example/MyObject">
    <interface name="com.example.MyObject">
    <method name="ManyArgs">
    <arg type="u" name="x" direction="in" />
    <arg type="s" name="str" direction="in" />
    <arg type="d" name="trouble" direction="in" />
    <arg type="d" name="d_ret" direction="out" />
    <arg type="s" name="str_ret" direction="out" />
    </method >
    </interface >
    </node >

    “in”标识输入参数,“out”标识输出参数。
    使用dbus-binding-tool工具来生成头文件,如dbus-binding-tool –mode=glib-client my-object.xml > my-object-bindings.h,会产生如下的内联函数原型:

    /* This is a blocking call */
    gboolean
    com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x,
    const char * IN_str, const gdouble IN_trouble,
    gdouble* OUT_d_ret, char ** OUT_str_ret,
    GError **error);

    /* This is a non-blocking call */
    DBusGProxyCall*
    com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x,
    const char * IN_str, const gdouble IN_trouble,
    com_example_MyObject_many_args_reply callback,
    gpointer userdata);

    /* This is the typedef for the non-blocking callback */
    typedef void
    (*com_example_MyObject_many_args_reply)
    (DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret,
    GError *error, gpointer userdata);

    所有函数的第一个参数都是DBusGProxy对象,一般是使用dbus_g_proxy_new_*函数创建出来的。客户端发送方法请求可以增加标记,目前只有org.freedesktop.DBus.GLib.NoReply标记,dbus可以不要回应消息,没有“out”参数,这样运算速度会快一点。

    server端的编写

    在GLib中,通过dbus表现出GObject,必须写XML文件描述这个对象的方法等属性。像上一篇文章中提到的例子:

    <?xml version="1.0" encoding="UTF-8" ?>
    <node name="/com/example/MyObject">
    <interface name="com.example.MyObject">
    <method name="ManyArgs">
    <arg type="u" name="x" direction="in" />
    <arg type="s" name="str" direction="in" />
    <arg type="d" name="trouble" direction="in" />
    <arg type="d" name="d_ret" direction="out" />
    <arg type="s" name="str_ret" direction="out" />
    </method >
    </interface >
    </node >

    一旦写完XML,运行dbus-binding-tool工具,如 dbus-binding-tool –mode=glib-server my-object.xml > my-object-glue.h.

    然后在本地代码中include产生的头文件,调用dbus_g_object_class_install_info进行类的初始化,传递对象和对象信息进去,如 dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info);每个对象类都需要这样做。

    为了执行方法,需要定义一个C函数,如my_object_many_args,需要遵守的规则如下:
    1.函数返回gboolean,true表示成功,false标识失败。
    2.第一个参数必须是对象实例的指针。
    3.跟在实例指针后面的参数是方法的输入参数。
    4.输入参数后面是输出参数。
    5.最后一个参数必须是GError **,如果函数返回失败,必须使用g_set_error填充该错误参数。
    如下的xml文件

    <method name="Increment">
    <arg type="u" name="x" />
    <arg type="u" direction="out" />
    </method>

    对应的函数定义为:
    gboolean
    my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);

    最后可以使用dbus_g_connection_register_g_object输出一个对象,如
    dbus_g_connection_register_g_object (connection,”/com/foo/MyObject”, obj);

    server端的声明(Annotations):
    org.freedesktop.DBus.GLib.CSymbol
    org.freedesktop.DBus.GLib.Async
    org.freedesktop.DBus.GLib.Const
    org.freedesktop.DBus.GLib.ReturnVal

     

    dbus启动问题

     

    首先需要启动守护进程
    dbus-daemon –system –print-pid –print-address
    结果提示 Failed to start message bus: Could not get UID and GID for username “messagebus”
    dbus需要有一个messagebus用户,创建该用户即可,useradd messagebus,问题解决。

    执行一个dbus测试程序,提示:D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open “/usr/var/lib/dbus/machine-id”: No such file or directory
    没有machine-id文件,查了一下,需要给它定义一个id,使用dbus-uuidgen >/usr/var/lib/dbus/machine-id
    产生这个文件,该问题解决。

    再次执行测试程序,又有问题:Couldn’t connect to session bus: Failed to execute dbus-launch to autolaunch D-Bus session,看了帮助http://dbus.freedesktop.org/doc/dbus-launch.1.html
    AUTOMATIC LAUNCHING一节,需要设置DBUS_SESSION_BUS_ADDRESS环境变量的值,先执行dbus-launch,获得了DBUS_SESSION_BUS_ADDRESS值,再export一下,最后执行测试程序,OK了

    在dbus帮助中有一篇关于dbus-launch的文章,可以在脚本中启动dbus-launch,同时自动设置DBUS_SESSION_BUS_ADDRESS环境变量,脚本文件rundbus如下:

    if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
    ## if not found, launch a new one
    eval `dbus-launch --sh-syntax --exit-with-session`
    echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
    fi

    执行. rundbus即可。

    展开全文
  • D-Bus学习笔记

    2010-12-22 15:33:00
    D-Bus最主要的用途是在Linux桌面环境为进程提供通信,同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。D-Bus的主要概率为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,...

    1.  进程间使用D-Bus通信

    D-Bus是一种高级的进程间通信机制,它由freedesktop.org项目提供,使用GPL许可证发行。D-Bus最主要的用途是在Linux桌面环境为进程提供通信,同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。D-Bus的主要概率为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,例如等待网络状态的转变或者计算机发出关机指令。目前,D-Bus已被大多数Linux发行版所采用,开发者可使用D-Bus实现各种复杂的进程间通信任务。

    2.  D-Bus的基本概念

    D-Bus是一个消息总线系统,其功能已涵盖进程间通信的所有需求,并具备一些特殊的用途。D-Bus是三层架构的进程间通信系统,其中包括:

    接口层:接口层由函数库libdbus提供,进程可通过该库使用D-Bus的能力。

    总线层:总线层实际上是由D-Bus总线守护进程提供的。它在Linux系统启动时运行,负责进程间的消息路由和传递,其中包括Linux内核和Linux桌面环境的消息传递。

    包装层:包装层一系列基于特定应用程序框架的Wrapper库。

    D-Bus具备自身的协议,协议基于二进制数据设计,与数据结构和编码方式无关。该协议无需对数据进行序列化,保证了信息传递的高效性。无论是libdbus,还是D-Bus总线守护进程,均不需要太大的系统开销。

    总线是D-Bus的进程间通信机制,一个系统中通常存在多条总线,这些总线由D-Bus总线守护进程管理。最重要的总线为系统总线(System Bus),Linux内核引导时,该总线就已被装入内存。只有Linux内核、Linux桌面环境和权限较高的程序才能向该总线写入消息,以此保障系统安全性,防止有恶意进程假冒Linux发送消息。

    会话总线(Session Buses)由普通进程创建,可同时存在多条。会话总线属于某个进程私有,它用于进程间传递消息。

    进程必须注册后才能收到总线中的消息,并且可同时连接到多条总线中。D-Bus提供了匹配器(Matchers)使进程可以有选择性的接收消息,另外运行进程注册回调函数,在收到指定消息时进行处理。匹配器的功能等同与路由,用于避免处理无关消息造成进程的性能下降。除此以外,D-Bus机制的重要概念有以下几个。

    对象:对象是封装后的匹配器与回调函数,它以对等(peer-to-peer)协议使每个消息都有一个源地址和一个目的地址。这些地址又称为对象路径,或者称之为总线名称。对象的接口是回调函数,它以类似C++的虚拟函数实现。当一个进程注册到某个总线时,都要创建相应的消息对象。

    消息:D-Bus的消息分为信号(signals)、方法调用(method calls)、方法返回(method returns)和错误(errors)。信号是最基本的消息,注册的进程可简单地发送信号到总线上,其他进程通过总线读取消息。方法调用是通过总线传递参数,执行另一个进程接口函数的机制,用于某个进程控制另一个进程。方法返回是注册的进程在收到相关信息后,自动做出反应的机制,由回调函数实现。错误是信号的一种,是注册进程错误处理机制之一。

    服务:服务(Services)是进程注册的抽象。进程注册某个地址后,即可获得对应总线的服务。D-Bus提供了服务查询接口,进程可通过该接口查询某个服务是否存在。或者在服务结束时自动收到来自系统的消息。

    建立服务的流程:
    ----------------------------------
        建立一个dbus连接之后 -- dbus_bus_get(),为这个dbus连接(DbusConnection)起名 -- dbus_bus_request_name(),这个名字将会成为我们在后续进行远程调用的时候的服务名,然后我们进入监听循环 -- dbus_connection_read_write()。在循环中,我们从总线上取出消息 -- dbus_connection_pop_message(),并通过比对消息中的方法接口名和方法名 -- dbus_message_is_method_call(),如果一致,那么我们跳转到相应的处理中去。在相应的处理中,我们会从消息中取出远程调用的参数。并且建立起回传结果的通路 -- reply_to_method_call()。回传动作本身等同于一次不需要等待结果的远程调用。
    发送信号的流程:
    ----------------------------------
        建立一个dbus连接之后,为这个dbus连接起名,建立一个发送信号的通道,注意,在建立通道的函数中,需要我们填写该信号的接口名和信号名 -- dbus_message_new_signal()。然后我们把信号对应的相关参数压进去 -- dbus_message_iter_init_append(); dbus_message_iter_append_basic()。然后就可以启动发送了 -- dbus_connection_send(); dbus_connection_flush。
    进行一次远程调用的流程:
    ----------------------------------
        建立好dbus连接之后,为这dbus连接命名,申请一个远程调用通道 -- dbus_message_new_method_call(),注意,在申请远程调用通道的时候,需要填写服务器名,本次调用的接口名,和本次调用名(方法名)。压入本次调用的参数 -- dbus_message_iter_init_append(); dbus_message_iter_append_basic(),实际上是申请了一个首地址,我们就是把我们真正要传的参数,往这个首地址里面送(送完之后一般都会判断是否内存越界了)。然后就是启动发送调用并释放发送相关的消息结构 -- dbus_connection_send_with_reply()。这个启动函数中带有一个句柄。我们马上会阻塞等待这个句柄给我们带回总线上回传的消息。当这个句柄回传消息之后,我们从消息结构中分离出参数。用dbus提供的函数提取参数的类型和参数 -- dbus_message_iter_init(); dbus_message_iter_next(); dbus_message_iter_get_arg_type(); dbus_message_iter_get_basic()。也就达成了我们进行本次远程调用的目的了。
    信号接收流程:
    ----------------------------------
        建立一个dbus连接之后,为这个dbus连接起名,为我们将要进行的消息循环添加匹配条件(就是通过信号名和信号接口名来进行匹配控制的) -- dbus_bus_add_match()。我们进入等待循环后,只需要对信号名,信号接口名进行判断就可以分别处理各种信号了。在各个处理分支上。我们可以分离出消息中的参数。对参数类型进行判断和其他的处理。
    dbus_connection_read_write()
    --------------------------------------
        As long as the connection is open, this function will block until it can read or write, then read or write, then return #TRUE.
        If the connection is closed, the function returns #FALSE.
    dbus_connection_pop_message()
    --------------------------------------
        Returns the first-received message from the incoming message queue, removing it from the queue. The caller owns a reference to the returned message. If the queue is empty, returns #NULL.
    dbus_connection_send()
    --------------------------------------
        Adds a message to the outgoing message queue. Does not block to write the message to the network; that happens asynchronously. To force the message to be written, call dbus_connection_flush(). Because this only queues the message, the only reason it can
    fail is lack of memory. Even if the connection is disconnected, no error will be returned.
        @param connection the connection.
        @param message the message to write.
        @param serial return location for message serial, or #NULL if you don't care
        @returns #TRUE on success.
    dbus_connection_send_with_reply()
    --------------------------------------
        Queues a message to send, as with dbus_connection_send(), but also returns a #DBusPendingCall used to receive a reply to the message. If no reply is received in the given timeout_milliseconds, this function expires the pending reply and generates a synthetic error reply (generated in-process, not by the remote application) indicating that a timeout occurred.
        A #DBusPendingCall will see a reply message before any filters or registered object path handlers. See dbus_connection_dispatch() for details on when handlers are run.
        A #DBusPendingCall will always see exactly one reply message, unless it's cancelled with dbus_pending_call_cancel().
        If #NULL is passed for the pending_return, the #DBusPendingCall will still be generated internally, and used to track the message reply timeout. This means a timeout error will occur if no reply arrives, unlike with dbus_connection_send().
        If -1 is passed for the timeout, a sane default timeout is used. -1 is typically the best value for the timeout for this reason, unless you want a very short or very long timeout. There is no way to avoid a timeout entirely, other than passing INT_MAX for the
    timeout to mean "very long timeout." libdbus clamps an INT_MAX timeout down to a few hours timeout though.
        @warning if the connection is disconnected, the #DBusPendingCall will be set to #NULL, so be careful with this.
        @param connection the connection
        @param message the message to send
        @param pending_return return location for a #DBusPendingCall object, or #NULL if connection is disconnected
        @param timeout_milliseconds timeout in milliseconds or -1 for default
        @returns #FALSE if no memory, #TRUE otherwise.
    dbus_message_is_signal()
    --------------------------------------
        Checks whether the message is a signal with the given interface and member fields. If the message is not #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field, returns #FALSE.
    dbus_message_iter_init()
    --------------------------------------
        Initializes a #DBusMessageIter for reading the arguments of the message passed in.
    dbus_message_iter_next()
    --------------------------------------
        Moves the iterator to the next field, if any. If there's no next field, returns #FALSE. If the iterator moves forward, returns #TRUE.
    dbus_message_iter_get_arg_type()
    --------------------------------------
        Returns the argument type of the argument that the message iterator points to. If the iterator is at the end of the message, returns #DBUS_TYPE_INVALID.
    dbus_message_iter_get_basic()
    --------------------------------------
        Reads a basic-typed value from the message iterator. Basic types are the non-containers such as integer and string.
    dbus_message_new_signal()
    --------------------------------------
        Constructs a new message representing a signal emission. Returns #NULL if memory can't be allocated for the message. A signal is identified by its originating object path, interface, and the name of the signal.
        Path, interface, and signal name must all be valid (the D-Bus specification defines the syntax of these fields).
        @param path the path to the object emitting the signal
        @param interface the interface the signal is emitted from
        @param name name of the signal
        @returns a new DBusMessage, free with dbus_message_unref()
    dbus_message_iter_init_append()
    --------------------------------------
        Initializes a #DBusMessageIter for appending arguments to the end of a message.
        @param message the message
        @param iter pointer to an iterator to initialize
    dbus_message_iter_append_basic()
    --------------------------------------
        Appends a basic-typed value to the message. The basic types are the non-container types such as integer and string.
        @param iter the append iterator
        @param type the type of the value
        @param value the address of the value
        @returns #FALSE if not enough memory
    dbus_message_new_method_call()
    --------------------------------------
        Constructs a new message to invoke a method on a remote object. Returns #NULL if memory can't be allocated for the message. The destination may be #NULL in which case no destination is set; this is appropriate when using D-Bus in a peer-to-peer context (no message bus). The interface may be #NULL, which means that if multiple methods with the given name exist it is undefined which one will be invoked.
        The path and method names may not be #NULL.
        Destination, path, interface, and method name can't contain any invalid characters (see the D-Bus specification).
        @param destination name that the message should be sent to or #NULL
        @param path object path the message should be sent to
        @param interface interface to invoke method on, or #NULL
        @param method method to invoke
        @returns a new DBusMessage, free with dbus_message_unref()
    dbus_bus_get()
    --------------------------------------
        Connects to a bus daemon and registers the client with it. If a connection to the bus already exists, then that connection is returned. The caller of this function owns a reference to the bus.
        @param type bus type
        @param error address where an error can be returned.
        @returns a #DBusConnection with new ref
    dbus_bus_request_name()
    --------------------------------------
        Asks the bus to assign the given name to this connection by invoking the RequestName method on the bus.
        First you should know that for each bus name, the bus stores a queue of connections that would like to own it. Only one owns it at a time - called the primary owner. If the primary owner releases the name or disconnects, then the next owner in the queue atomically takes over.
        So for example if you have an application org.freedesktop.TextEditor and multiple instances of it can be run, you can have all of them sitting in the queue. The first one to start up will receive messages sent to org.freedesktop.TextEditor, but if that one exits another will become the primary owner and receive messages.
        The queue means you don't need to manually watch for the current owner to disappear and then request the name again.
        @param connection the connection
        @param name the name to request
        @param flags flags
        @param error location to store the error
        @returns a result code, -1 if error is set
        给DBusConnection起名字(命名) -- 两个相互通信的连接(connection)不能同名
        命名规则: xxx.xxx (zeng.xiaolong)
    dbus_bus_add_match()
    --------------------------------------
        Adds a match rule to match messages going through the message bus. The "rule" argument is the string form of a match rule.
        @param connection connection to the message bus
        @param rule textual form of match rule
        @param error location to store any errors
    dbus_pending_call_block()
    --------------------------------------
        Block until the pending call is completed. The blocking is as with dbus_connection_send_with_reply_and_block(); it does not enter the main loop or process other messages, it simply waits for the reply in question.
        If the pending call is already completed, this function returns immediately.
        @todo when you start blocking, the timeout is reset, but it should really only use time remaining since the pending call was created. This requires storing timestamps instead of intervals in the timeout
        @param pending the pending call
    dbus_pending_call_steal_reply()
    --------------------------------------
        Gets the reply, or returns #NULL if none has been received yet. Ownership of the reply message passes to the caller. This function can only be called once per pending call, since the reply message is tranferred to the caller.
        @param pending the pending call
        @returns the reply message or #NULL.

    安装D-Bus可在其官方网站下载源码编译,地址为http://dbus.freedesktop.org。或者在终端上输入下列指令:

    1.  
      1. yum install dbus dbus-devel dbus-doc

    安装后,头文件位于"/usr/include/dbus-<版本号>/dbus"目录中,编译使用D-Bus的程序时需加入编译指令"`pkg-config --cflags --libs dbus-1`"。

    3.  D-Bus的用例

    在使用GNOME桌面环境的Linux系统中,通常用GLib库提供的函数来管理总线。在测试下列用例前,首先需要安装GTK+开发包(见22.3节)并配置编译环境。该用例一共包含两个程序文件,每个程序文件需单独编译成为可执行文件。

    1.消息发送程序

    "dbus-ding-send.c"程序每秒通过会话总线发送一个参数为字符串Ding!的信号。该程序的源代码如下:

    1. #include <glib.h>                               // 包含glib库  
    2. #include <dbus/dbus-glib.h>                     // 包含
      glib库中D-Bus管理库  
    3. #include <stdio.h> 
    4. static gboolean send_ding(DBusConnection *bus);// 定义发送消息函数的原型  
    5. int main ()  
    6. {  
    7.    GMainLoop *loop;                             // 定义一个事件循环对象的指针  
    8.    DBusConnection *bus;                         // 定义总线连接对象的指针  
    9.    DBusError error;                             // 定义D-Bus错误消息对象  
    10.    loop = g_main_loop_new(NULL, FALSE);         // 创建新事件循环对象  
    11.    dbus_error_init (&error);                    // 将错误消息对象连接到D-Bus  
    12.                                                 // 错误消息对象  
    13.    bus = dbus_bus_get(DBUS_BUS_SESSION, &error);// 连接到总线  
    14.    if (!bus) {                              // 判断是否连接错误  
    15. g_warning("连接到D-Bus失败: %s", error.message);  
    16.                                         // 使用GLib输出错误警告信息  
    17.       dbus_error_free(&error);              // 清除错误消息  
    18.       return 1;  
    19.    }  
    20.    dbus_connection_setup_with_g_main(bus, NULL);  
    21.                                             // 将总线设为接收GLib事件循环  
    22.    g_timeout_add(1000, (GSourceFunc)send_ding, bus);  
    23.                                     // 每隔1000ms调用一次send_ding()函数  
    24.                                             // 将总线指针作为参数  
    25.    g_main_loop_run(loop);                   // 启动事件循环  
    26.    return 0;  
    27. }  
    28. static gboolean send_ding(DBusConnection *bus)  // 定义发
      送消息函数的细节  
    29. {  
    30.    DBusMessage *message;                        // 创建消息对象指针  
    31.    message = dbus_message_new_signal("/com/burtonini/dbus/ding",   
    32.                                        "com.burtonini.dbus.Signal",  
    33.                                        "ding");     // 创建消息对象并标识路径  
    34.    dbus_message_append_args(message,  
    35.                             DBUS_TYPE_STRING, "ding!",  
    36.                             DBUS_TYPE_INVALID);     //将字符串Ding!定义为消息  
    37.    dbus_connection_send(bus, message, NULL);    // 发送该消息  
    38.    dbus_message_unref(message);                 // 释放消息对象  
    39.    g_print("ding!/n");                          // 该函数等同与标准输入输出                                    
    40.    return TRUE;  
    41. }

    main()函数创建一个GLib事件循环,获得会话总线的一个连接,并将D-Bus事件处理集成到GLib事件循环之中。然后它创建了一个名为send_ding()函数作为间隔为一秒的计时器,并启动事件循环。send_ding()函数构造一个来自于对象路径"/com/burtonini/dbus/ding"和接口"com.burtonini.dbus.Signal"的新的Ding信号。然后,字符串Ding!作为参数添加到信号中并通过总线发送。在标准输出中会打印一条消息以让用户知道发送了一个信号。

    2.消息接收程序

    dbus-ding-listen.c程序通过会话总线接收dbus-ding-send.c程序发送到消息。该程序的源代码如下:

    1. #include <glib.h>                               // 包含glib库  
    2. #include <dbus/dbus-glib.h>                     // 包含glib库中D-Bus管理库  
    3. static DBusHandlerResult signal_filter      // 定义接收消息函数的原型  
    4.       (DBusConnection *connection, DBusMessage *message, void *user_data);  
    5. int main()  
    6. {  
    7.    GMainLoop *loop;                             // 定义一个事件循环对象的指针  
    8.    DBusConnection *bus;                         // 定义总线连接对象的指针  
    9.    DBusError error;                             // 定义D-Bus错误消息对象  
    10.    loop = g_main_loop_new(NULL, FALSE);         // 创建新事件循环对象  
    11.    dbus_error_init(&error);                     // 将错误消息对象连接到D-Bus  
    12.                                                 // 错误消息对象  
    13.    bus = dbus_bus_get(DBUS_BUS_SESSION, &error);    // 连接到总线  
    14.    if (!bus) {                              // 判断是否连接错误  
    15. g_warning("连接到D-Bus失败: %s", error.message);  
    16.                                         // 使用GLib输出错误警告信息  
    17.       dbus_error_free(&error);              // 清除错误消息  
    18.       return 1;  
    19.   }  
    20.    dbus_connection_setup_with_g_main(bus, NULL);      
    21.                                             // 将总线设为接收GLib事件循环  
    22.    dbus_bus_add_match(bus, "type='signal',interface
      ='com.burtonini.dbus.Signal'");  // 定义匹配器  
    23.    dbus_connection_add_filter(bus, signal_filter, loop, NULL);  
    24.                                             // 调用函数接收消息  
    25.    g_main_loop_run(loop);                   // 启动事件循环  
    26.    return 0;  
    27. }  
    28. static DBusHandlerResult                    // 定义接收消息函数的细节  
    29. signal_filter (DBusConnection *connection,
      DBusMessage *message, void *user_data)  
    30. {  
    31.    GMainLoop *loop = user_data;             // 定义事件循环对象的指针,并与主函数中的同步  
    32.    if (dbus_message_is_signal               // 接收连接成功消息,判断是否连接失败  
    33.         (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
      "Disconnected")) {  
    34.       g_main_loop_quit (loop);              // 退出主循环  
    35.       return DBUS_HANDLER_RESULT_HANDLED;  
    36.    }  
    37.    if (dbus_message_is_signal(message, "com.burtonini.dbus.Signal",   
    38.    "Ping")) {  
    39.                                             // 指定消息对象路径,判断是否成功  
    40.       DBusError error;                      // 定义错误对象  
    41.       char *s;  
    42. dbus_error_init(&error);                // 将错误消息对象连接到D-Bus错误  
    43.                                         // 消息对象  
    44.       if (dbus_message_get_args                 // 接收消息,并判断是否有错误  
    45.          (message, &error, DBUS_TYPE_STRING, &s,
      DBUS_TYPE_INVALID)) {  
    46.          g_print("接收到的消息是: %s/n", s);   // 输出接收到的消息  
    47.          dbus_free (s);                     // 清除该消息  
    48.       }   
    49.       else {                                    // 有错误时执行下列语句  
    50.          g_print("消息已收到,但有错误提示: %s/n", error.message);  
    51.          dbus_error_free (&error);  
    52.       }  
    53.       return DBUS_HANDLER_RESULT_HANDLED;  
    54.    }  
    55.    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  
    56. }

    该程序侦听dbus-ping-send.c程序正在发出的信号。main()函数和前面一样启动,创建一个到总线的连接。然后它声明愿意在使用com.burtonini.dbus.Signal接口的信号被发送时得到通知,将signal_filter()函数设置为通知函数,然后进入事件循环。当满足匹配的消息被发送时,signal_func()函数会被调用。

    如果需要确定在接收消息时如何处理,可通过检测消息头实现。若收到的消息为总线断开信号,则主事件循环将被终止,因为监听的总线已经不存在了。若收到其他的消息,首先将收到的消息与期待的消息进行比较,两者相同则输出其中参数,并退出程序。两者不相同则告知总线并没有处理该消息,这样消息会继续保留在总线中供别的程序处理。

    展开全文
  • D-BUS 是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux® 桌面之中。了解创建它的原因、它的用途以及发展前景。 D-BUS 本质上是 进程间通信(inter-process communication)(IPC)的一个实现。不过...

    D-BUS 是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux® 桌面之中。了解创建它的原因、它的用途以及发展前景。

    D-BUS 本质上是 进程间通信(inter-process communication)(IPC)的一个实现。不过,有一些特性使得 D-BUS 远远不是“只是另一个 IPC 实现”。有很多不同的 IPC 实现,因为每一个都定位于解决特定的明确定义的问题。CORBA 是用于面向对象编程中复杂的 IPC 的一个强大的解决方案。DCOP 是一个较轻量级的 IPC 框架,功能较少,但是可以很好地集成到 K 桌面环境中。SOAP 和 XML-RPC 设计用于 Web 服务,因而使用 HTTP 作为其传输协议。D-BUS 设计用于桌面应用程序和 OS 通信。

    桌面应用程序通信

    典 型的桌面都会有多个应用程序在运行,而且,它们经常需要彼此进行通信。DCOP 是一个用于 KDE 的解决方案,但是它依赖于 Qt,所以不能用于其他桌面环境之中。类似的,Bonobo 是一个用于 GNOME 的解决方案,但是非常笨重,因为它是基于 CORBA 的。它还依赖于 GObject,所以也不能用于 GNOME 之外。 D-BUS 的目标是将 DCOP 和 Bonobo 替换为简单的 IPC,并集成这两种桌面环境。由于尽可能地减少了 D-BUS 所需的依赖,所以其他可能会使用 D-BUS 的应用程序不用担心引入过多依赖。

    桌面/操作系统通信

    术 语“操作系统”在这里不仅包括内核,还包括系统后台进程。例如,通过使用 D-BUS 的 udev(Linux 2.6 中取代 devfs 的,提供动态 /dev 目录),当设备(比如一个 USB 照相机)插入时会发放出一个信号。这样可以更紧密地将硬件集成到桌面中,从而改善用户体验。

    D-BUS 特性

    D-BUS 有一些有趣的特性,使其像是一个非常有前途的选择。

    协 议是低延迟而且低开销的,设计得小而高效,以便最小化传送的往返时间。另外,协议是二进制的,而不是文本的,这样就排除了费时的序列化过程。由于只面向本 地机器处理的使用情形,所以所有的消息都以其自然字节次序发送。字节次序在每个消息中声明,所以如果一个 D-BUS 消息通过网络传输到远程的主机,它仍可以被正确地识别出来。

    从开发者的角度来看,D-BUS 是易于使用的。有线协议容易理解,客户机程序库以直观的方式对其进行包装。

    程 序库还设计用于为其他系统所包装。预期,GNOME 将使用 GObject 创建包装 D-BUS 的包装器(实际上这些已经部分存在了,将 D-BUS 集成入它们的事件循环),KDE 将使用 Qt 创建类似的包装器。由于 Python 具有面向对象特性和灵活的类型,已经有了具备类似接口的 Python 包装器。

    最后,D-BUS 正在 freedesktop.org 的保护下进行开发,在那里,来自 GNOME、KDE 以及其他组织的对此感兴趣的成员参与了设计与实现。

    D-BUS 的内部工作方式

    典 型的 D-BUS 设置将由几个总线构成。将有一个持久的 系统总线(system bus),它在引导时就会启动。这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序不能欺骗系统事件。还将有很多 会话总线(session buses),这些总线当用户登录后启动,属于那个用户私有。它是用户的应用程序用来通信的一个会话总线。当然,如果一个应用程序需要接收来自系统总线的 消息,它不如直接连接到系统总线 —— 不过,它可以发送的消息将是受限的。

    一 旦应用程序连接到了一个总线,它们就必须通过添加 匹配器(matchers) 来声明它们希望收到哪种消息。匹配器为可以基于接口、对象路径和方法进行接收的消息指定一组规则(见后)。这样就使得应用程序可以集中精力去处理它们想处 理的内容,以实现消息的高效路由,并保持总线上消息的预期数量,以使得不会因为这些消息导致所有应用程序的性能下降并变得很慢。

    对象

    本 质上,D-BUS 是一个对等(peer-to-peer)的协议 —— 每个消息都有一个源和一个目的。这些地址被指定为 对象路径。概念上,所有使用 D-BUS 的应用程序都包括一组 对象,消息发送到或者发送自特定对象 —— 不是应用程序 —— 这些对象由对象路径来标识。

    另 外,每个对象都可以支持一个或多个 接口(interfaces)。这些接口看起来类似于 Java 中的接口或者 C++ 中的纯粹的虚类(pure virtual classes)。不过,没有选项来检查对象是否实现了它们所声明的接口,而且也没有办法可以调查对象内部以使列出其支持的接口。接口用于名称空间和方法 名称,因此一个单独的对象可以有名称相同而接口不同的多个方法。

    消息

    在 D-BUS 中有四种类型的消息:方法调用(method calls)、方法返回(method returns)、信号(signals)和错误(errors)。要执行 D-BUS 对象的方法,您需要向对象发送一个方法调用消息。它将完成一些处理并返回一个方法返回消息或者错误消息。信号的不同之处在于它们不返回任何内容:既没有 “信号返回”消息,也没有任何类型的错误消息。

    消息也可以有任意的参数。参数是强类型的,类型的范围是从基本的非派生类型(布尔(booleans)、字节(bytes)、整型(integers))到高层次数据结构(字符串(strings)、数组( arrays)和字典(dictionaries))。

    服务

    服 务(Services) 是 D-BUS 的最高层次抽象,它们的实现当前还在不断发展变化。应用程序可以通过一个总线来注册一个服务,如果成功,则应用程序就已经 获得 了那个服务。其他应用程序可以检查在总线上是否已经存在一个特定的服务,如果没有可以要求总线启动它。服务抽象的细节 —— 尤其是服务活化 —— 当前正处于发展之中,应该会有变化。

    用例

    尽 管 D-BUS 相对较新,但是却迅速地得到了采用。如前所述,可以构建具有 D-BUS 支持的 udev 以使得当热插拔(hot-plug)设备时它可以发送一个信号。任何应用程序都可以侦听这些事件并当接收到这些事件时执行动作。例如,gnome- volume-manager 可以检测到 USB 存储棒的插入并自动挂载它;或者,当插入一个数码相机时它可以自动下载照片。

    一 个更为有趣但很不实用的例子是 Jamboree 和 Ringaling 的结合。Jamboree 是一个简单的音乐播放器,它具有 D-BUS 接口,以使得它可以被告知播放、到下一首歌、改变音量等等。Ringaling 是一个小程序,它打开 /dev/ttyS0(一个串行端口)并观察接收到的内容。当 Ringaling 发现文本“RING”时,就通过 D-BUS 告知 Jamboree 减小音量。最终的结果是,如果您的计算机上插入了一个调制解调器,而且电话铃响,则音乐音量就会为您减小。这 正是计算机所追求的!

    代码示例

    现在,让我们来接触一些使用 D-BUS 代码的示例。

    dbus-ping-send.c 每秒通过会话总线发送一个参数为字符串“Ping!”的信号。我使用 Glib 来管理总线,以使得我不需要自己来处理总线的连接细节。

    清单 1. dbus-ping-send.c

    #include <glib.h>
      #include <dbus/dbus-glib.h>
      
      static gboolean send_ping (DBusConnection *bus);
      
      int
      main (int argc, char **argv)
      {
       GMainLoop *loop;
       DBusConnection *bus;
       DBusError error;
      
       /* Create a new event loop to run in */
       loop = g_main_loop_new (NULL, FALSE);
      
       /* Get a connection to the session bus */
       dbus_error_init (&error);
       bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
       if (!bus) {
        g_warning ("Failed to connect to the D-BUS
    daemon: %s", error.message);
        dbus_error_free (&error);
        return 1;
       }
      
       /* Set up this connection to work in a GLib event loop */
       dbus_connection_setup_with_g_main (bus, NULL);
       /* Every second call send_ping() with the bus as an argument*/
       g_timeout_add (1000, (GSourceFunc)send_ping, bus);
      
       /* Start the event loop */
       g_main_loop_run (loop);
       return 0;
      }
      
      static gboolean
      send_ping (DBusConnection *bus)
      {
       DBusMessage *message;
      
       /* Create a new signal "Ping" on the
    "com.burtonini.dbus.Signal" interface,
        * from the object "/com/burtonini/dbus/ping". */
       message = dbus_message_new_signal
    ("/com/burtonini/dbus/ping",
          "com.burtonini.dbus.Signal", "Ping");
       /* Append the string "Ping!" to the signal */
       dbus_message_append_args (message,
                    DBUS_TYPE_STRING, "Ping!",
                    DBUS_TYPE_INVALID);
       /* Send the signal */
       dbus_connection_send (bus, message, NULL);
       /* Free the signal now we have finished with it */
       dbus_message_unref (message);
       /* Tell the user we send a signal */
       g_print("Ping!/n");
       /* Return TRUE to tell the event loop
    we want to be called again */
       return TRUE;
      }

    main 函数创建一个 GLib 事件循环,获得会话总线的一个连接,并将 D-BUS 事件处理集成到 Glib 事件循环之中。然后它创建了一个名为 send_ping 间隔为一秒的计时器,并启动事件循环。

    Linux联盟收集整理 
    展开全文
  • D-Bus的方式在移动手机操作系统中非常重要,包括Maemo,Moblin等以Linux为基础的操作系统。估计Andriod也大量使用。D-Bus的相关学习资料见:http://www.freedesktop.org/wiki/Software/dbus,在网上也有大量的学习...
  • D-Bus是一种高级的进程间通信机制,在Linux桌面为进程提供通信。是一种低开销、低延时的IPC,并被多种桌面环境(如 KDE、GNOME等)采用。 D-Bus是一个消息总线系统,其功能已涵盖进程间通信的所有需求,并具备...
  • D-BUS详解

    2013-10-24 13:43:53
    一、概述  官方网站:http://www.freedesktop.org/wiki/Software/dbus,但是如果要下...可以从svn上拿,具体见后面的dbus编译部分。  从官方首页中可以看到这样一段描述D-BUS 的话:“D-Bus is a message b
  • 大家在使用D-Bus的过程中,对于D-Bus出现的各种异常往往束手无策,很大一部分原因就是D-Bus没有很好的调试工具,仅仅是几个dbus-send, dbus-monitor等,调试监测效果并不好。 现在,有新的D-Bus调试工具发布出来了...
  •  D-Bus实质上一个适用于桌面应用的进程间的通讯机制,即所谓的IPC(inter-processcommunication)机制。它最初产生于Linux平台,是做为freedesktop.org项目的一部分来开发的。现在已经深入地渗透到Lin
  • Qt D-Bus

    2015-01-16 14:43:53
     D-Bus是为Linux系统开发的进程间通信(IPC)和远程过程调用(RPC)机制,使用统一的通信协议来代替现有的各种IPC解决方案。它允许系统级进程(如:打印机和硬件驱动服务)和普通用户进程进行通信。  它使用一个...
  • ssh Client failed to connect to the D-BUS daemon GConf-WARNING **: Client failed to connect to the D-BUS daemon: Failed to connect to socket /tmp/dbus-*****: Connection refused   Add the ...
  • 最近遇到了一个问题,在centos7的容器中service启动服务会报错Failed to get D-Bus connection: Operation not permitted [root@ng8w7c7 /]# service ng8w status Redirecting to /bin/systemctl status ng8w....
  • 在Centos7的docker里装好了httpd,运行报错: ...Failed to get D-Bus connection: Operation not permitted 真无语啊,必须提权才可以: docker run --privileged -d -p 10080:80 centos /sbin/init
  • D-Bus daemon的启动

    2012-03-09 12:10:08
    D-Bus daemon是D-Bus的非常重要的一个服务,类似于IP网络中的路由器。 跟这个后台服务有关的应用程序包括: dbus-daemon: D-Bus的后台进程,作为D-Bus的消息中转枢纽,可分成system和session两种。 dbus-launch: ...
  • D-BUS简介

    2013-03-18 22:45:20
    D-Bus最主要的用途是在Linux桌面环境为进程提供通信,同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。D-Bus的主要概率为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,...
  • 在使用docker for windows开启saltstack容器的时候,执行以下语句报错 ...Failed to get D-Bus connection: Operation not permitted 搜索后发现,在开启容器的时候需要加上特权privileged=true,且需要在加...
  • 报错: Failed to get D-Bus connection: Operation not permitted 解决方案 先启动docker 用该命令创建 docker run -d -e "container=docker" --privileged=true -v /sys/fs/cgroup:/sys/fs/cgroup --...
  • 参考 : https://askubuntu.com/questions/627621/no-object-for-d-bus-interface-when-mounting-with-nautilus 1. 打开 GParted 2. 选择无法挂载的HDD 3. 右键选择 New UUID!!!注意!!不能对windows系统盘...
  • 报错的原因: 在运行的docker容器中 执行命令启动nginx [root@node132 ~]# docker run -it nginx-1 /bin/bash [root@03e74fb601c1 /]# ...Failed to get D-Bus connection: Operation not permitted 如...
1 2 3 4 5 ... 20
收藏数 41,926
精华内容 16,770
热门标签