如何用wampp 做网站,什么是网页?,90后做受网站,网络策划公司全网天下Qt D-Bus概述 一、概述二、总线三、相关概念1. 消息2. 服务名称3. 对象的路径4. 接口5. 备忘单 四、调试五、使用Qt D-Bus 适配器1. 在 D-Bus 适配器中声明槽函数1. 异步槽2. 只输入槽3. 输入输出槽4. 自动回复5. 延迟回复 一、概述 
D-Bus是一种进程间通信(IPC)和远程过程调用… Qt D-Bus概述 一、概述二、总线三、相关概念1. 消息2. 服务名称3. 对象的路径4. 接口5. 备忘单 四、调试五、使用Qt D-Bus 适配器1. 在 D-Bus 适配器中声明槽函数1. 异步槽2. 只输入槽3. 输入输出槽4. 自动回复5. 延迟回复   一、概述 
D-Bus是一种进程间通信(IPC)和远程过程调用(RPC)机制最初是为Linux开发的用一个统一的协议取代现有的和竞争的IPC解决方案。它还被设计为允许系统级进程(如打印机和硬件驱动程序服务)和普通用户进程之间的通信。 
它使用快速的二进制消息传递协议由于其低延迟和低开销适合于同机通信。它的规范目前由 freedesktop.org 项目定义所有各方都可以使用。 
通信通常通过称为“总线”(因此得名)的中央服务器应用程序进行但也可以直接进行应用程序到应用程序的通信。当在总线上通信时应用程序可以查询哪些其他应用程序和服务可用以及按需激活其中一个。 
二、总线 
D-Bus总线用于需要多对多通信的情况。为了实现这一点在任何应用程序可以连接到总线之前启动一个中央服务器该服务器负责跟踪连接的应用程序并负责将消息从源路由到目的地。 
此外D-Bus还定义了两个众所周知的总线称为系统总线和会话总线。这些总线的特殊之处在于它们具有良好定义的语义:一些服务被定义为可以在这些总线中的一个或两个中找到。 
例如希望查询附加到计算机上的硬件设备列表的应用程序可能会与系统总线上可用的服务通信而提供打开用户web浏览器的服务可能会在会话总线上找到。 
在系统总线上还可以找到关于允许每个应用程序提供哪些服务的限制。因此可以合理地确定如果存在某个服务它是由受信任的应用程序提供的。 
三、相关概念 
1. 消息 
在底层应用程序通过D-Bus相互发送消息进行通信。消息用于转发远程过程调用以及与之相关的应答和错误。当在总线上使用时消息有目的地这意味着它们只被路由到感兴趣的各方避免了由于“蜂群”或广播造成的拥塞。 
然而有一种特殊类型的消息称为“信号消息”(基于Qt的信号和槽机制的概念)它没有预定义的目的地。由于其目的是在一对多上下文中使用因此信号消息被设计为通过“选择加入”机制工作。 
Qt D-Bus模块将消息的低级概念完全封装为Qt开发人员熟悉的更简单的面向对象方法。在大多数情况下开发人员无需担心发送或接收消息。 
2. 服务名称 
当通过总线进行通信时应用程序获得所谓的 “服务名称” 这是该应用程序选择被同一总线上的其他应用程序所知道的方式。通信总得知道是谁收谁发嘛。服务名称由D-Bus总线守护进程代理用于将消息从一个应用程序路由到另一个应用程序。与服务名称类似的概念是IP地址和主机名一台计算机通常有一个IP地址并可能有一个或多个与之关联的主机名这取决于它向网络提供的服务。 
另一方面如果不使用总线也不会使用服务名称。如果我们再次将其与计算机网络进行比较这将等同于点对点网络:由于对等点是已知的因此不需要使用主机名来查找它或它的IP地址。 
D-Bus服务名称的格式实际上与主机名非常相似它是由点分隔的字母和数字序列。常见的做法甚至是根据定义该服务的组织的域名来命名服务名称。 
例如D-Bus服务是由freedesktop.org定义的可以在总线上的服务名称下找到它: org.freedesktop.DBus就像 deepin中的部分代码用到的这种服务名称也是用的域名表示方式java中的很多包名也用的域名表示 
QDBusConnection sessionBus  QDBusConnection::sessionBus();
if (!sessionBus.interface()-isServiceRegistered(com.deepin.daemon.InputDevices)) {qDebug()  DBusError  com.deepin.daemon.InputDevices;
return;
}// 监控全局鼠标信号。
sessionBus.connect(com.deepin.daemon.InputDevices,/com/deepin/api/XEventMonitor, com.deepin.api.XEventMonitor, ButtonPress,this, SLOT(ButtonPressEvent(int, int, int, QString)));3. 对象的路径 
与网络主机一样应用程序通过导出对象向其他应用程序提供特定的服务。这些对象是分层组织的很像从QObject派生的类所拥有的父子关系。然而一个不同之处在于存在 “根对象” 的概念所有对象都有作为最终父对象的根对象。 如果我们继续对Web服务进行类比对象路径等同于URL的路径部分:  
与它们类似D-Bus中的对象路径的形式类似于文件系统中的路径名称它们是由斜杠分隔的标签每个标签由字母、数字和下划线(“_”)组成。它们必须总是以斜杠开始不能以斜杠结束。 
4. 接口 
接口类似于c抽象类和Java的interface关键字并声明了在调用者和被调用者之间建立的“契约”。也就是说它们建立了可用的方法、信号和属性的名称以及在建立通信时期望的任何一方的行为。 
Qt在它的插件系统中使用了一个非常相似的机制c中的基类通过Q_DECLARE_INTERFACE()宏与一个唯一标识符相关联。 
实际上D-Bus接口名称的命名方式类似于Qt插件系统所建议的:一个标识符通常由定义该接口的实体的域名构造而成。 
5. 备忘单 
为方便记忆命名格式及其用途可使用下表: 
d - bus概念类比名字的格式Service name 服务名称网络主机名点分隔(“看起来像主机名”)Object path 对象路径URL路径组件斜杠分隔(“看起来像一条路径”)Interface 接口插件标识符以圆点分隔 
四、调试 
在开发使用D-Bus的应用程序时有时能够查看每个应用程序通过总线发送和接收的消息的相关信息是很有用的。 
通过在运行每个应用程序之前设置QDBUS_DEBUG环境变量可以在每个应用程序的基础上启用该特性。例如在D-Bus遥控汽车示例中我们可以通过以下方式运行控制器和汽车使能仅对汽车进行调试: examples/dbus/remotecontrolledcar/controller/controller QDBUS_DEBUG1 examples/dbus/remotecontrolledcar/car/car 有关消息的信息将写入启动应用程序的控制台中。 
五、使用Qt D-Bus 适配器 
适配器是附加到任何qobject派生类的特殊类并使用D-Bus提供与外部世界的接口。适配器旨在成为轻量级类其主要目的是中继对真实对象的调用和来自真实对象的调用可能会验证或转换来自外部世界的输入从而保护真实对象。 与多重继承不同适配器可以随时添加到任何对象(但不能删除)这在导出现有类时提供了更大的灵活性。适配器的另一个优点是在不同接口中的同名方法中提供类似但不相同的功能在向对象添加新版本的标准接口时这种情况非常常见。 
为了使用适配器必须创建继承QDBusAbstractAdaptor的类。由于这是一个标准的qobject派生类Q_OBJECT宏必须出现在声明中源文件必须用moc工具处理。类还必须包含一个带有“D-Bus Interface”名称的Q_CLASSINFO条目声明它要导出的接口。每个类只支持一个条目。 
类中的任何公共槽都可以通过MethodCall类型的消息通过总线访问。(更多信息请参见声明D-Bus适配器的槽函数)。课堂上的信号将通过D-Bus自动传递。然而并非所有类型都允许信号或槽的参数列表参见Qt D-Bus类型系统了解更多信息。 
此外使用Q_PROPERTY声明的任何属性都将通过D-Bus上的Properties接口自动公开。由于QObject属性系统不允许非可读属性因此不可能使用适配器声明只写属性。 
1. 在 D-Bus 适配器中声明槽函数 
D-Bus适配器中的槽函数就像普通的公共槽函数一样被声明但是它们的参数必须遵循一定的规则(参见Qt D-Bus类型系统了解更多信息)。如果槽函数的参数不符合这些规则或者槽函数不是公共的那么D-Bus将无法访问这些槽函数。 
槽可以有一个const QDBusMessage 类型的参数它必须出现在输入参数列表的末尾在任何输出参数之前。如果存在此参数将使用正在处理的当前消息的副本初始化这允许被调用方获取有关调用方的信息例如其连接名称。 
槽有三种类型: 
异步槽只输入槽输入和输出槽 
1. 异步槽 
异步槽通常不向调用者返回任何应答。因此它们不能接受任何输出参数。在大多数情况下到运行槽的第一行时调用方函数已经恢复工作。 
然而槽函数不能依赖于这种行为。调度和消息调度问题可能会改变槽函数运行的顺序。打算与调用者同步的代码应该提供自己的同步方法。 
异步槽由方法签名中的关键字Q_NOREPLY标记位于void返回类型和槽名之前。D-Bus Complex乒乓示例中的quit()槽函数就是这样的一个例子。 
2. 只输入槽 
仅输入槽是普通槽它接受按值或常量引用传递的参数。然而与异步槽不同调用方通常在恢复操作之前等待被调用方完成。因此非异步槽函数不应该阻塞或者应该在文档中说明它们可能会阻塞。 
只有输入的槽在它们的签名中没有特殊的标记除了它们只接受通过值或常量引用传递的参数。槽可以选择将QDBusMessage参数作为最后一个参数该参数可用于执行对方法调用消息的附加分析。 
3. 输入输出槽 
与仅输入槽一样输入-输出槽是调用者等待回复的槽。但是与只输入的应答不同此应答将包含数据。输出数据的槽可能包含非常量引用也可能返回一个值。但是输出参数必须全部出现在参数列表的末尾并且输入参数不能交错。可选地QDBusMessage参数可能出现在输入和输出参数之间。 
4. 自动回复 
方法应答是由Qt D-Bus实现与输出参数(如果有的话)的内容一起自动生成的。槽函数不需要考虑构造适当的QDBusMessage对象并通过连接发送它们。 
然而这样做的可能性仍然存在。如果槽发现它需要发送一个特殊的回复甚至是一个错误它可以在QDBusMessage参数上使用QDBusMessage::createReply()或QDBusMessage::createErrorReply()并使用QDBusConnection::send()发送它。如果槽函数这样做了Qt D-Bus实现将不会生成任何应答。 
警告:当调用者调用方法并等待应答时它将只等待有限的时间。打算花费很长时间来完成的槽函数应该在文档中明确这一事实以便调用者适当地设置更高的超时。 
5. 延迟回复 
在某些情况下被调用的槽可能无法立即处理请求。当请求涉及可能阻塞的I/O或网络操作时这种情况经常发生。 如果是这种情况slot应该将控制返回给应用程序的主循环以避免冻结用户界面并在以后恢复该进程。要实现这一点它应该利用输入参数列表末尾的额外QDBusMessage参数并请求延迟回复。 
为此我们编写一个将请求数据存储在持久结构中的槽并使用QDBusMessage::setDelayedReply(true)向调用者指示稍后将发送响应。 struct RequestData{QString request;QString processedData;QDBusMessage reply;};QString processRequest(const QString request, const QDBusMessage message){RequestData *data  new RequestData;data-request  request;message.setDelayedReply(true);data-reply  message.createReply();QDBusConnection::sessionBus().send(data-reply);appendRequest(data);return QString();}需要使用QDBusConnection::sessionBus().send(data-reply)来显式地通知调用者响应将被延迟。在这种情况下返回值并不重要;我们返回一个任意值来满足编译器。 
当请求被处理并且应答可用时应该使用获得的QDBusMessage对象发送应答。在我们的示例中回复代码可能如下所示: void sendReply(RequestData *data){// data-processedData has been initialized with the requests replyQDBusMessage reply  data-reply;// send the reply over D-Bus:reply  data-processedData;QDBusConnection::sessionBus().send(reply);// dispose of the transaction datadelete data;}在这个例子中可以看到当延迟应答到位时从槽返回的值将被Qt D-Bus忽略。它们仅用于在与远程应用程序通信适配器描述时确定槽函数的签名或者在槽函数中的代码决定不使用延迟应答的情况下。 
延迟的回复本身是通过调用QDBusMessage::reply()从Qt D-Bus请求的。然后被调用的代码负责最终向调用方发送应答。 
警告-当调用者调用方法并等待应答时它将只等待有限的时间。打算花费很长时间来完成的槽函数应该在文档中明确这一事实以便调用者适当地设置更高的超时。