QtDBus编程详解(比较差)

DBus的出现,使得Linux进程间通信更加便捷,不仅可以和用户空间应用程序进行通信,而且还可以和内核的程序进行通信,可以说DBus使得Linux变得更加智能,更加具有交互性。我们可以把DBus看做是一个消息总线(bus) 
 
DBus分为两种类型:
system bus(系统总线):用于系统(Linux)和用户程序之间进行通信和消息的传递。
session bus(会话总线):用于桌面(e.g. GNOME, KDE....)用户程序之间进行通信。一般我们用到的就是session bus。

object path
在我们通常C++中,都会有object这个概念,用类创建一个实例就是一个object。在DBus通信中,这种由类定义的object叫native object。在DBus通信中,将一个object(native, remote)对象和一个路径绑定,当我们需要和该native object通信的时候,我们只需要把消息发送到该路径。这个路径就叫object path。正因为是路径,所以object的格式斜杠作为分隔(/object/example)
 
DBus name
总线名,这是对每一个连接到Dbus上的连接进行标示。每一个连接到session ,system bus的连接也叫做Dbus。当创建连接成功之后,系统会给该总线分配一个唯一的名称,这个unique name通常是以":"开头,比如 :45-7等等。类比:DBus name 好比IP地址。
 Service name
服务名称。即DBus上提供的服务的名称。一个DBus可以提供多种服务。类比:hostname。
DBus通信的时候,连接到DBus之后,需要向系统注册服务,告知系统,我需要向外界提供何种服务。Service name是以点作为分隔(org.demo.myservice)

Interface 
接口。在DBus中,interface类比于C++中的namespace。Interface内部是一些列的method和signal.这些method和signal都可以通过DBus通信发送消息进行调用。

以上概念看起来很模糊。我写了一个简单的DBus通信程序,并用工具对系统中的DBus进行观察。

 

 

我创建了一个DBus连接,系统分配的unique name名称是:(:1.93)
我创建了两个Server:
org.feiyinzilgd.DBusExample.one
org.feiyinzilgd.DBusExample.two
这两个service的DBus unique name都是(:1.93)
即:一个DBus总线上,提供了两个服务。

有两个Object path:
/
/Car

Object path提供了很多interface,例如:com.trolltech.Examples.Carinterface.
该interface下面提供了一些列的methods和signal.

 

QtDBus通信,就必须有服务端和客户端(关键是弄清楚哪一端是server,哪一端是client)。

server:

1.申请一个总线连接,连接到system dbus或者是session dbus。

2.在总线上挂服务,使得其他进程可以请求和查询服务。

service服务,相当于hostname,当我发送消息的时候,我们需要确定发送到哪一个host。只有跟总线注册了service之后,外部进程才可以查询和发送消息。

3.在挂载的服务上注册一个执行服务的对象。

对于Qt来说,是面向对象的。那么,QtDBus或者是进程通信,实际上背后还是两个对象在通信。那么同样,我们需要为该host提供一个可执行服务的对象(即可以发送、接收消息以及做其他的相关处理的对象)。

上面的3已经说得很清楚了。通信不管有没有DBus,通信的背后始终是两个对象在对话。普通的Qt的对象是无法实现与DBus通信的。出于方便和安全考虑,QtDBus有一个DBsu适配器adaptor的概念,该DBus adaptor的目的是实现消息的转发。适配器,是可以加载也可以卸载的而且是附着在Qt普通对象上的,当普通的Qt对象想要和DBus总线通信的时候,只需要告诉这个附着在它身上的DBus adaptor,让这个适配器去转发或者代替他接收消息。这就是QDBusAbstractAdaptor类的工作,这个类就是用来创建dbus 适配器的。只有server才需要适配器,client不需要适配器,但是需要另一种接口。

现在就编写代码来说明以上几个步骤:

Car *car = new Car();
//...

new CarInterfaceAdaptor(car);
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerObject("/Car", car);
connection.registerService("com.trolltect.CarExample");

以上代码就完成了以上的所有步骤,让我们来看看上述代码究竟做了些什么。

Car就是需要和DBus通信的server Qt的普通对象(不具有DBus功能)。

/**
为通信server对象car安装一个DBus adaptor适配器,从而使得具有DBus功能
*/
new CarInterfaceAdaptor(car)

其中CarInterfaceAdaptor是一个派生于QDBusAbstractAdaptor的一个类。

/**
创建一个连接到session总线上的链接connection
*/
QDBusConnection connection = QDBusConnection::sessionBus();


/**
注册com.trolltech.CarExample这个service
*/
connection.registerService("com.trolltech.CarExample");

/**
注册一个可执行的对象。这个对象就是我们所说的已经安装了DBus适配器的Qt普通对象。不过这个Qt对象已经具备了DBus功能
*/
connection.registerObject("/Car", car);

 

注册service成功之后,你就可以使用D-Feet这个工具观察到你已经连接到session上了,并有一个com.trolltech.CarExample服务了

Qt自带的工具qdbusviewer也可以观察到,但是我个人不太喜欢使用qdbusviewer,D-Feet比它更加强大。

 

Client:

1.申请一个总线连接,连接到system dbus或者是session dbus上。

2.创建一个接口,连接到要请求的服务上。

上面已经提到了。Server需要一个适配器,而Client则需要一个接口

3.发送请求。

在Client中,接口是派生于QDBusAbstractInterface的一个类。这个类使得Client具有和远端的Server具有通信能力。

Client和Server之间进行DBus通信,很大程度上是Client去调用Server提供的一些method和signals。那么这个接口其实就是一个proxy代理。让你操作remote的Server上的method和signals就像操作本地函数一样。这也就是QDBusAbstractInterface派生类的主要作用。

同样,下面我将结合代码来具体的讲述:

 CarInterface *car;
car = new CarInterface("com.trolltech.CarExample", "/Car",
                           QDBusConnection::sessionBus(), this);

————————————————
版权声明:本文为CSDN博主「谭海燕」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feiyinzilgd/article/details/6081914