当前位置: 首页 > 编程日记 > 正文

linux+Qt 下利用D-Bus进行进程间高效通信的三种方式

linux+Qt 下利用D-Bus进行进程间高效通信的三种方式

原文链接:
https://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html

D-Bus概述
什么是D-Bus?

D-Bus是一种进程间通信的机制,它被设计成为一种低开销、低延迟的IPC,并被多种桌面环境(如KDE、GNOME等)所采用。
关于D-Bus的详细介绍可以参考freedesktop.org提供的两份文档, D-Bus Tutorial 和 D-Bus Specification 。
基本概念

D-Bus提供了多种Message Bus用于应用程序之间的通信。通常,Linux发行版都会提供两种Message Bus:System Bus和Session Bus。System Bus 主要用于内核和一些系统全局的service之间通信;Session Bus 主要用于桌面应用程序之间的通信。
D-Bus中用于通信的基本单元叫做Message,Message的具体格式可以参考 D-Bus Specification 。
当应用程序连接到M essage Bus上时,D-Bus会分配一个unique connection name,这个unique name通常的格式如":34-907"。Unique name以":“开头,后面的数字没有特别的意义,只是为了保证这个unique name的唯一性。
另外,应用程序还可以向Message Bus请求一个well-known name,格式如同一个反置的域名,例如"com.mycompany.myapp”。当一个应用程序连接到Message Bus上时,可以拥有两种名称:unique connection name和well-known name。这两种名称的关系可以理解为网络上的IP地址和域名的关系。
在D-Bus规范里,unique connection name和well-known name都叫做Bus Name。这点比较奇怪,也比较拗口,Bus Name并不是Message Bus的名称,而是应用程序和Message Bus之间的连接的名称。
应用程序和Message Bus之间的连接也被称为Service,这样一来,把Bus Name称作Service Name在概念上会更清晰一点。
当应用程序连接到Message Bus上时,该应用程序可以在Bus上创建一到多个Object(我们可以把D-Bus的object理解成面向对象语言里的object)。Service通过Object 为其他应用程序提供访问接口。因为在Message Bus上,一个应用程序可以对应多个Object,所以不同的Object必须由Object Path(类似于文件系统的路径)来区分。Object Path的格式如"/foo/bar"。
对于Service Name和Object Path,QT4文档中有一个类比还是比较直观的,如下图所示:

图中的ftp.example.com可以看作是Service Name,/pub/something可以看作是Object Path。

D-Bus通过Signal/Method来发送和接收Message。Signal/Method可以理解为QT4中的Signal/Slot这个概念。一个Object可以提供多个Method/Signal,这些Method/Signal的集合又组成了Interface。

因此,D-Bus的这些概念从大到小可以表示为:Message Bus->Service->Object->[Interface]->Method/Signal。

其中,Interface是可选的。

D-Bus 调试工具

常用的D-Bus调试工具有 D-Feet、qdbusviewer等。
在C onsole窗口中键入qdbusviewer命令可以打开QT自带的qdbusviewer 。
在这里插入图片描述

如上图所示,我们可以通过qdbusviewer来调用Object在Message Bus上发布的所有Method。

D -Bus 的 QT4 绑定

下面,我们通过一个实例来介绍D-Bus的QT4绑定。(参见hotel.pro)
我们在Session bus上创建一个"com.test.hotel" service,通过这个service可以执行check in,check out和query三个动作。

注: 一个通过service的名称来确定进程,即每个进程应该有一个自己的service,而不是多进程共用一个service,我在初期就犯了这个错,想通过在一个service下注册不同的Object来区别各个进程,

实际上这是不可行的,Object的作用是用来区分一个进程内多个通信对象的Object, service名称不可相同, 如果你只有一个进程间需要通信的DbusObject, 例如:

你在两个进程里分别注册 名字为 com.zyl.test 和 com.zyl.test1 的两个service, 然后分别在各自的service中 注册 名字为/testObject 的dbus 对象, 然后创建 在com.zyl.test 的进程中创建

service name 为com.zyl.test1 , path 为 /testObject 的 接口对象, 在com.zyl.test1 的进程中创建service name 为com.zyl.test , path 为 /testObject 的 接口对象, 即可实现双方的互相调用

注册service
在这里插入图片描述

注册Object
在这里插入图片描述

创建proxy代理对象并且调用
在这里插入图片描述

创建Service并且注册Object

int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 用于建立到session bus的连接QDBusConnection bus = QDBusConnection::sessionBus();// 在session bus上注册名为"com.test.hotel"的serviceif (!bus.registerService("com.test.hotel")) {qDebug() << bus.lastError().message();exit(1);}Hotel my_hotel;// 注册名为"/hotel/registry"的object。// "QDBusConnection::ExportAllSlots"表示把类Hotel的所有Slot都导出为这个Object的methodbus.registerObject("/hotel/registry", &my_hotel,QDBusConnection::ExportAllSlots);return a.exec();
}

我们再看一下Hotel类的定义。

class Hotel : public QObject
{Q_OBJECT// 定义Interface名称为"com.test.hotel.registry"Q_CLASSINFO("D-Bus Interface", "com.test.hotel.registry")
public:Hotel() { m_rooms = MAX_ROOMS; }
public slots:// Check in,参数为房间数,返回成功拿到的房间数int checkIn(int num_room);// Check out,参数为房间数,返回成功退回的房间数int checkOut(int num_room);// Query,用于查询目前还剩下的房间数int query();
private:int m_rooms;QReadWriteLock m_lock;
};

运行这个程序,我们可以使用qdbusviewer查看和操作这个Object。

通过QDBusMessage访问Service
在QT4中,用QDBusMessage表示在D-Bus上发送和接收的Message。(参见checkin.pro)

// 用来构造一个在D-Bus上传递的Message
QDBusMessage m = QDBusMessage::createMethodCall("com.test.hotel","/hotel/registry","com.test.hotel.registry","checkIn");
if (argc == 2) {// 给QDBusMessage增加一个参数;// 这是一种比较友好的写法,也可以用setArguments来实现m << QString(argv[1]).toInt();
}
// 发送Message
QDBusMessage response = QDBusConnection::sessionBus().call(m);
// 判断Method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) {// QDBusMessage的arguments不仅可以用来存储发送的参数,也用来存储返回值;// 这里取得checkIn的返回值int num_room = response.arguments().takeFirst().toInt();printf("Got %d %s\n", num_room, (num_room > 1) ? "rooms" : "room");
} else {fprintf(stderr, "Check In fail!\n");
}

通过QDBusInterface 访问Service

在QT4中,QDBusInterface可以更加方便的访问Service。(参见checkin2.pro)

// 创建QDBusInterface
QDBusInterface iface( "com.test.hotel", "/hotel/registry","com.test.hotel.registry", QDBusConnection::sessionBus());
if (!iface.isValid()) {qDebug() << qPrintable(QDBusConnection::sessionBus().lastError().message());exit(1);
}
// 呼叫远程的checkIn,参数为num_room
QDBusReply<int> reply = iface.call("checkIn", num_room);
if (reply.isValid()) {num_room = reply.value();printf("Got %d %s\n", num_room, (num_room > 1) ? "rooms" : "room");
} else {fprintf(stderr, "Check In fail!\n");
}

看,用QDBusInterface来访问Service是不是更加方便?

从D-Bus XML自动生成Proxy类

用QDB usInterface访问Service已经非常方便了,但还不够直观。还有没有更直观的方法,就像访问本地类成员变量的方式访问远程的method?答案是Proxy。

Proxy Object提供了一种更加直观的方式来访问Service,就好像调用本地对象的方法一样。

概括的说,达成上述目标需要分三步走:

(1)使用工具qdbuscpp2xml从hotel.h生成XML文件;

            qdbuscpp2xml -M hotel.h -o com.test.hotel.xml

(2)使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类;

            qdbusxml2cpp com.test.hotel.xml -i hotel.h -p hotelInterface
   这条命令会生成两个文件:hotelInterface.cpp和hotelInterface.h

(3)调用(2)生成的类来访问Service。

Qt 5.11里, 可以不再使用工具从xml来导出 继承自QDBusInterface的类,

只需在pro文件中添加xml文件名称则可自动导出并且识别
在这里插入图片描述
在这里插入图片描述

代理类的使用方式为
在这里插入图片描述

注意: 不可以将代理类作为成员变量在原始类中使用,这样会造成互相包含的编译问题,
在这里插入图片描述

我这里使用的是全局变量的形式,使用代理类的槽和本地的信号槽一样,甚至还可以有返回值

下面是举例(参见checkin3.pro ):

// 初始化自动生成的Proxy类com::test::hotel::registry
com::test::hotel::registry myHotel("com.test.hotel","/hotel/registry",QDBusConnection::sessionBus());
// 调用checkIn
QDBusPendingReply<int> reply = myHotel.checkIn(num_room);
// qdbusxml2cpp生成的Proxy类是采用异步的方式来传递Message,
// 所以在此需要调用waitForFinished来等到Message执行完成
reply.waitForFinished();
if (reply.isValid()) {num_room = reply.value();printf("Got %d %s\n", num_room, (num_room > 1) ? "rooms" : "room");
} else {fprintf(stderr, "Check In fail!\n");
} 

使用Adapter注册Object

如前文所述,我们可以直接把class Hotel注册为Message Bus上的一个Object,但这种方式并不是QT4所推荐的。QT4推荐使用Adapter来注册Object。
很多情况下,我们可能只需要把我们定义的类里的方法有选择的发布到Message Bus上,使用Adapter可以很方便的实现这种意图。
以前文中的Hotel为例,假设我们只需要把checkIn和checkOut发布到Message Bus上,应该怎么办?

(1)使用工具 qdbuscpp2xml从hotel.h生成XML文件;

            qdbuscpp2xml -M hotel.h -o com.test.hotel.xml 

(2)编辑com.test.hotel.xml,把其中的query部分去掉;
即去掉以下三条语句:
<method name="query"> <arg type="i" direction="out"/> </method>
(3)使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类;
qdbusxml2cpp com.test.hotel.xml -i hotel.h -a hotelAdaptor
这条命令会生成两个文件:hotelAdaptor.cpp和hotelAdaptor.h
(4)调用(3)生成的类来注册Object。

(参见hotel2.pro)

int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QDBusConnection bus = QDBusConnection::sessionBus();Hotel myHotel;// RegistryAdaptor是qdbusxml2cpp生成的Adaptor类RegistryAdaptor myAdaptor(&myHotel);if (!bus.registerService("com.test.hotel")) {qDebug() << bus.lastError().message();exit(1);}bus.registerObject("/hotel/registry", &myHotel);return a.exec();
}

运行这个应用程序,我们从qdbusviewer上可以看到,只有checkIn和checkOut两个method被发布。如下图所示:
在这里插入图片描述

自动启动Service
D-Bus系统提供了一种机制可以在访问某个service时,自动把该程序运行起来。sr/share/dbus-1/services下面建立com.test.hotel.service文件,文件的内容如下:
[D-BUS Service]Name=com.test.hotelExec=/path/to/your/hotel
这样,我们在访问Hotel的method之前,就不必手动运行该应用程序了。

相关文章:

xbmc-12.0稳定版代码初探 (2) —— XBMC_HOME

XBMC工程在debug时要设置XBMC_HOME的环境 用于指定ffmpeg的Dll文件位置&#xff0c;语言等等 xbmc/filesystem/SpecialProtocol.cpp 定义了一些如&#xff1a; CSpecialProtocol::SetXBMCPath();的函数 xbmc\Application.cpp InitDirectoriesWin32(); -> CUtil::GetHomePat…

python是最好的语言 永远二十岁_Python是世界上最好的语言吗?

编程语言的选择是IT圈子永远的争议。在任意一个程序员聚集的场合&#xff0c;喊一句类似于“PHP是世界上最好的语言”这样的话&#xff0c;肯定会惹来不少人和你争论得面红耳赤。那么&#xff0c;python是世界上最好的语言吗&#xff1f;这个我不敢说&#xff0c;但是至少他应该…

(转)Android笔记--handler机制

一、重要参考资料 【参考资料】目前来看&#xff0c;下面的几个网址中的内容质量比较不错&#xff0c;基本不需要再读别的网址了。1、android消息机制一http://xtfncel.javaeye.com/blog/6635172、Android消息机制二http://xtfncel.javaeye.com/blog/6635183、Android线程间通信…

自制操作系统Antz(9)——实现内核 (下) 实现图形化界面

Antz系统更新地址&#xff1a; https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址&#xff1a;https://www.cnblogs.com/LexMoon/category/1267413.html Github项目地址&#xff1a;https://github.com/CasterWx/AntzOS 在前几天的任务中&#xff…

python迷宫万花筒代码_利用广度优先遍历搜索迷宫的python源代码

广度优先遍历简称为DFS&#xff0c;是数据结构中比较常用的一个算法&#xff0c;主要原理是采用队列先进先出的规则&#xff0c;一层一层的访问图的节点。而迷宫问题接近与遍历&#xff0c;但是不同于遍历&#xff0c;主要考虑是采用栈的形式标记路径&#xff0c;并对当前节点和…

联想拯救者Y9000-ubuntu-nvidia-驱动安装

概述 由于联想拯救者Y9000的硬件都比较新&#xff0c;所以在安装ubuntu 的时候会有很多驱动的问题&#xff0c;本文主要讲解安装nvidia驱动的问题&#xff0c;如网卡、触摸板无效的其他问题请在我的其他文章中查找 友情提示 安装完系统之后先插网线装ssh服务&#xff0c; 确…

修改远程桌面端口

修改远程桌面端口需要两个步骤&#xff1a;  1、打开注册表 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]&#xff0c;修改右边PortNamber的值&#xff0c;其默认值是3389&#xff0c;修改成所希望的端口即可&#xff0c;例如3…

开发管理 CheckLists(4) -风险管理

本文章主要介绍在项目启动前怎么样分步骤的去识别风险,才去什么方式去识别风险. 有需要做风险识别的朋友可以按照下面的步骤简单的走上一遍,或者可以提高项目的成功率 注意&#xff1a;本文章只是你做风险识别的chekcLists ,上面提到的一些分析方法都只是简单的介绍…

python的深拷贝与浅拷贝

对于list, set, dict来说, 直接赋值. 其实是把内存地址交给变量. 并不是复制⼀份内容. 两个变量的内容其实为一个地址,如果要在复制的同时分配新的地址则需要用到深拷贝和浅拷贝的命令 lst1 ["何炅", "杜海涛","周渝⺠", ["麻花藤", …

safari post 请求接收不到_我是谁?我在哪?我要到哪去?——HTTP请求头

各位小白帽们好又到了新一期的知识点咯在正片开始之前再次提醒一下各位因为联盟管理的需要本周五(12月4日)5点半将会对各位在平台的答题分数进行统计筛选部分排名靠前的童鞋作为核心的正式会员考核压力来了大家是不是有点紧张呢只要积极学习知识积极参与答题向本AI卖萌要flag相…

SharePoint 2013 配置开发环境,需安装VS2012插件

SharePoint 2013已经安装好了&#xff0c;接下来就是配置开发环境&#xff0c;安装VS2012&#xff0c;但是&#xff0c;装好了以后&#xff0c;发现没有SharePoint 2013开发的支持&#xff0c;如下图&#xff1a; 然后&#xff0c;去网上查找资料&#xff0c;VS2012对SharePoin…

联想拯救者Y9000-ubuntu-U盘启动失败解决方法

注意事项 1、U盘要是USB3.0的U盘&#xff0c;否则基本会失败 安装到最后的时候报一个 cd/dvd 设备 low speed的故障 2、bios 设置 硬盘模式 选择 AHCImode 模式&#xff0c; 否则刷机不成功 3、 U盘镜像的烧录方式&#xff0c; 实测windows 下的rufus工具有效

RedHat Enterprise 5.1下OpenLDAP的配置及PAMNSS的配置

服务器端 192.1.0.160 客户机端 192.1.0.221 一、在服务器端配置LDAP服务&#xff1a; 1.下载 openldap-2.4.11.tar.gz和db-4.7.25.tar.gz 2.安装BerkeleyDB #rpm -qa|grep db # tar xvf db-4.7.25.tar.gz # cd db_4.7.25# cd build_unix/# ../dist/configure -prefix/usr/loca…

pwn with glibc heap(堆利用手册)

前言 ​ 对一些有趣的堆相关的漏洞的利用做一个记录&#xff0c;如有差错&#xff0c;请见谅。 ​ 文中未做说明 均是指 glibc 2.23 ​ 相关引用已在文中进行了标注&#xff0c;如有遗漏&#xff0c;请提醒。 简单源码分析 ​ 本节只是简单跟读了一下 malloc 和 free 的源码&am…

COCO KeyPoints关键点数据集准备

COCO KeyPoints关键点数据集准备 概述 网上搜了一圈&#xff0c;coco关键点数据集准备的内容比较少&#xff0c;这里写一篇完成的标注流程到数据集准备的文章&#xff0c;以备后忘 标注工具 coco官方标注工具: coco–annotator https://github.com/jsbroks/coco-annotator …

Boost 1.53.0 发布,可移植的C++标准库

Boost 1.53.0 发布了&#xff0c;包含了 5 个新的库&#xff0c;修复了一些安全漏洞以及 Boost.Locale 组件的 bug 。 新增的 5 个库包括&#xff1a; Boost.AtomicBoost.CoroutineBoost.MultiprecisionBoost.Numeric.OdeintBoost.Lockfree完整改进记录说明请看 changelog 下载…

华为云客户端_从技术角度解读华为云手机之于普通用户的可行性

9月1日&#xff0c;华为云宣布&#xff0c;华为首创全球首个ARM芯片的“云手机”正式公测。此消息一出&#xff0c;普通消费市场一片赞美之声&#xff0c;想必大家更多的想法是终于让华为找到了一个应对当前手机困局的解决方案了。据悉&#xff0c;华为云鲲鹏手机早在今年3月就…

c#获取应用程序目录

string str1 Process.GetCurrentProcess().MainModule.FileName;//可获得当前执行的exe的文件名。 string str2Environment.CurrentDirectory;//获取和设置当前目录&#xff08;即该进程从中启动的目录&#xff09;的完全限定路径。//备注 按照定义&#xff0c;如果该进程在本…

【BZOJ5311/CF321E】贞鱼/Ciel and Gondolas(动态规划,凸优化,决策单调性)

【BZOJ5311/CF321E】贞鱼/Ciel and Gondolas&#xff08;动态规划&#xff0c;凸优化&#xff0c;决策单调性&#xff09; 题面 BZOJCF洛谷 辣鸡BZOJ卡常数&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 辣鸡BZOJ卡常数&#xff01;&#xff01;&…

python定时任务contrib_django+celery配置(定时任务+循环任务)

下面介绍一下djangocelery的配置做定时任务1.首先介绍一下环境和版本python2.7django 1.8.1celery 3.1.23django-celery 3.1.172.celery的安装sudo pip install celery3.1.23sudo pip install django-celery3.1.173.新建一个项目(1)django-admin startproject django_celery…

CenterNet KeyPoints 关键点训练自己的数据

概述 网上搜了一圈&#xff0c;关于CenterNet 训练关键点数据的资料非常少&#xff0c;而且讲得都很模糊&#xff0c;没法解决实际问题&#xff0c;也未说明细节和要素。在踏坑许久之后&#xff0c;才跑通CenterNet的关键点训练&#xff0c;于是记录一下踏坑历程&#xff0c;以…

Java学习笔记---字符类型

一、字符类型也算是整数类型的一种 字符类型在内存中占有2个字节&#xff0c;可以用来保存英文字母等字符。计算机处理字符类型时&#xff0c;是把这些字符当成不同的整数来看待&#xff0c;因此&#xff0c;严格说来&#xff0c;字符类型也算是整数类型的一种&#xff08;小写…

我的家庭私有云计划-16

嗯&#xff0c;上午测试S2S的稳定性&#xff0c;改掉几个bug。还挺忙的。这会儿让机器跑测试去&#xff0c;腾出点时间&#xff0c;我们接着聊。 呵呵&#xff0c;昨天哪&#xff0c;已经有朋友批评我了&#xff0c;说我有点贪大求全&#xff0c;这个论坛什么的没必要自己实现&…

“cyl projection cannot cross pole” 解决方法

解决方法&#xff1a; 1、尝试更新NumPy以及相关模块&#xff1a; 在CMD里面执行 conda update –all 遇到提示选择yes/y 更新完毕后看是否可以载入。 发现并不能成功更新&#xff0c;于是采取了下面方法&#xff1a; 2、如果方法一不能解决&#xff0c;那么尝试卸载相关库&…

使用ubuntu(18.04) 作为软路由器连接互联网

使用ubuntu&#xff08;18.04&#xff09; 作为软路由器连接互联网 背景: 最近要用ubuntu机器作为中继路由&#xff0c;需要配置一下&#xff0c;但是内网外网网上找了一圈&#xff0c;五花八门的&#xff0c;照着做没有一个靠谱的&#xff0c;遇到的问题也没有任何说明&#…

程序员肿么了?为何总被认为是“屌丝”

没有想到会这么多人&#xff0c;有一点我强调一下&#xff0c;我的标题是被认为&#xff0c;而不是说真是。其实程序员相比其他行业不见得差&#xff0c;只是社会整体认可度不高。&#xff08;或者说认知&#xff09; 本文纯属闲时娱乐&#xff0c;请勿当真&#xff0c;请勿较真…

python空值填充_pandas | DataFrame基础运算以及空值填充

今天是pandas数据处理专题的第四篇文章&#xff0c;我们一起来聊聊DataFrame的基本运算。上一篇文章当中我们介绍了DataFrame数据结构当中一些常用的索引的使用方法&#xff0c;比如iloc、loc以及逻辑索引等等。今天的文章我们来看看DataFrame的一些基本运算。数据对齐我们可以…

Python学习之路基础篇--10Python基础,函数进阶

1 命名空间 对于Python 来说命名空间一共有三种 1 内置命名空间 —— Python 解释器 就是Python 解释器一启动就可以使用的名字&#xff0c;储存在内置命名空间中。内置的名字在启动解释器的时候被加载进内存里 2 全局命名空间 —— 我们所命名的&#xff0c;但不是函数中的代码…

C语言中整型浮点型在计算机中的存储

第一次写博客&#xff0c;遣词造句有点菜&#xff0c;算是一次简单梳理&#xff0c;慢慢学习人家的博客风格&#xff0c;随着学习的深入再做修改。 本次学习的是C语言在VS下的编译调试&#xff0c;对于初学者两说&#xff0c;首先说一下如何监控变量&#xff0c;以及监控变量在…

判断交换机性能好坏的九个因素

【文章摘要】把握千兆交换机的主要性能指标是关键&#xff0c;而判断交换机性能的好坏&#xff0c;需要从以下几方面的因素出发... 把握千兆交换机的主要性能指标是关键&#xff0c;而判断交换机性能的好坏&#xff0c;需要从以下几方面的因素出发&#xff1a;   转发技术  …