Qt扫盲-Qt D-Bus概述

2024-04-30 04:12
文章标签 qt 概述 bus 扫盲

本文主要是介绍Qt扫盲-Qt D-Bus概述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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_DEBUG=1 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 request's 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请求的。然后,被调用的代码负责最终向调用方发送应答。

警告-当调用者调用方法并等待应答时,它将只等待有限的时间。打算花费很长时间来完成的槽函数应该在文档中明确这一事实,以便调用者适当地设置更高的超时。

这篇关于Qt扫盲-Qt D-Bus概述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/947877

相关文章

《计算机英语》Unit 1 Computer Overview 计算机概述

期末试卷组成 1、选择20道 2、判断20道 3、词汇翻译(单词+词组,参照课后习题) 4、翻译2道(一道原题,参照作业) SectionA About Computer 关于计算机 algorithm          n.  算法  operate          v.  操作  digital           adj. 数字的  integrated circuit

【云计算 复习】第1节 云计算概述和 GFS + chunk

一、云计算概述 1.云计算的商业模式 (1)软件即服务(SaaS) 有些景区给游客提供烧烤场地,游客需要自己挖坑或者砌烧烤台,然后买肉、串串、烧烤。 (2)平台即服务(PaaS) 有些景区给游客提供烧烤场地,同时搭建好烧烤台,游客只需要自己带食材和调料、串串、烧烤。 (3)基础设施即服务(IaaS) 有些景区给游客提供烧烤场地,同时搭建好烧烤台,还有专门的厨师来烧烤,用户不需要关心前面的所有

QT 中ListView和ListWidget有什么区别

ListView和ListWidget在Qt框架中都是用于显示列表数据的控件,但它们在使用方法和特性上存在一些明显的差异。以下是关于它们用法不一样的地方的详细分析: 数据管理方式: ListView:使用QAbstractItemModel数据模型来管理和显示列表数据。QAbstractItemModel是一个抽象类,允许开发者自定义数据模型以适应特定的数据结构和需求。这使得ListView在处

如何使用Qt的PIMPL习惯用法(PIMPL Idiom

) PIMPL是指“Pointer to IMPLementation”(指向实现的指针),意味着将实现细节隐藏起来,用户类无需关注这些实现细节。在Qt中常用PIMPL习惯用法来清晰地区分接口与实现,尽管Qt官方文档并未详细说明该机制。本文将演示如何在Qt中使用PIMPL习惯用法,并以一个简单的坐标输入对话框作为实例。 原理与动机 PIMPL的核心在于将类的实现细节封装在一个私有类中,这个私

【Qt6.3 基础教程 17】 Qt布局管理详解:创建直观和响应式UI界面

文章目录 前言布局管理的基础为什么需要布局管理器? 盒布局:水平和垂直排列小部件示例:创建水平盒布局 栅格布局:在网格中对齐小部件示例:创建栅格布局 表单布局:为表单创建标签和字段示例:创建表单布局 调整空间和伸缩性示例:增加弹性空间 总结 前言 当您开始使用Qt设计用户界面(UI)时,理解布局管理是至关重要的。布局管理不仅关系到UI的外观,更直接影响用户交互的体验。本篇博

【Qt6.3 基础教程 16】 掌握Qt中的时间和日期:QTimer和QDateTime的高效应用

文章目录 前言QTimer:定时任务的强大工具QTimer的基本用法高级特性:单次定时器 QDateTime:处理日期和时间获取当前日期和时间日期和时间的格式化输出日期和时间计算 用例:创建一个倒计时应用结论 前言 在开发桌面应用程序时,处理时间和日期是一个常见且重要的任务。Qt框架提供了强大的工具来处理与时间相关的功能,其中QTimer和QDateTime是最核心的类。本

Java——IO流(一)-(5/8):IO流概述、字节流-FileInputStream 每次读取一个字节

IO流概述 介绍 输入输出流,用于读写数据。 I指Input,称为输入流:负责把数据读到内存中去。 O指Output,称为输出流:负责写数据出去。 IO流的应用场景 文件内容的读写永久保存应用数据复制粘贴对话通信等等 怎么学IO流 理清楚IO六点分类和体系循序渐进、深入学习每个IO流的作用和用法 IO流的分类 IO流总体来看就有四大类: 字节输入流:以内存

基于ZYNQ7000的交叉编译工具链Qt+OpenCV+ffmpeg等库支持总结

最近刚刚接触XILINX的ZYNQ板,刚接触没有十天。XILINX定位它为SOC,我也很认同,起码比TI定位MPU为SOC强很多。据说今年TI的最新产品也加入了ZYNQ板。 之前的MIPS处理器设计与实现的项目就算做告一段落,搞了将近7个月,成果显著,收获颇多,最近打算搞搞ZYNQ。 之前MIPS也有一套交叉编译工具,不过是老师提供的,自己也尝试搞了搞,太辛苦了,而且也没什么成果,因为我

Qt 5.2.0 qwt-6.1.0

环境:win7(32) qt-5.2.0 qwt-6.1.0(qt-6.1.0说支持qt5以上的版本,但是我在配置前没找到最新的qt-5.2.0与qwt-6.1.0,其实步骤的差不多,暂时没发现版本引起的问题) 一.添加环境变量(在cmd测试下qmake,如果有问题重启电脑):  Add "C:\Qt\Qt5.0.1\5.0.1\mingw47_32\bin" to your systems

Android热修复学习之旅开篇——热修复概述

Android热修复技术无疑是Android领域近年来最火热的技术之一,同时也涌现了各种层出不穷的实现方案,如QQ空间补丁方案、阿里AndFix以及微信Tinker等等,从本篇博客开始,计划写一个系列博客专门介绍热修复的相关内容,本系列博客将一一介绍这些框架的原理和源码分析,作为本系列的开篇,本篇博客将对热修复技术进行一个概述,并对以上几种方案进行对比。 为什么会出现热修复? 简单来说,以前出