dbus的入门于应用--dbus的C编程接口

2023-11-21 18:38
文章标签 接口 入门 应用 编程 dbus

本文主要是介绍dbus的入门于应用--dbus的C编程接口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


大部分资料都讲了很多东西却最终没有让我搞清楚怎么用 DBus,不就是一个 IPC 通信的工具么?就没有一点实用些的资料么?看了很多资料之后还是觉得只见树木不见森林。仔细整理下思路,觉得还是应该从最基本的方面入门,先从 DBus 的 C API 入手学习,有了这些知识,就算麻烦,也可以先在完成一个基本功能的例子程序的同时大概的知道 DBus 的运行机制。


在网上找到这么一篇文章:http://www.matthew.ath.cx/misc/dbus, 正合我意,下面的内容基本是对这篇文章的翻译和扩充。


注意:


翻译没有得到原文作者同意,原文也很简单易懂,最好去读原文。如果收到投诉,我会立即撤掉本文的。
本文不是一篇好的 DBus 入门,有很多基本的东西不在记述之内。
一般情况下不会直接使用 C API 进行 DBus 的编程,而是使用某种 DBus-binding,但我觉得理解 DBus 的 C API 对完整地理解 DBus 是非常重要的。

虽然 DBus 是用 C 写的,而且本文写的是 C API,但是 DBus 设计中充满的面向对象的思想,请注意。


一、共通部分的代码
在使用 DBus 进行通信的时候,有一些代码是无论如何都会使用到的。首先,你必须要连接上 Dbus,一般来说,系统中会有一个 System Bus 和一个 Session Bus(他们的差别,请参考我另外的笔记)。其次,你需要在 Dbus 中注册一个名字,用于标识自己。为了简单起见,这里先不考虑重名的情况:

DBusError err;
DBusConnection* conn;
int ret;
// initialise the errors
dbus_error_init(&err);// connect to the bus
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {fprintf(stderr, "Connection Error (%s)\n", err.message);dbus_error_free(&err);
}
if (NULL == conn) {exit(1);
}
// request a name on the bus
ret = dbus_bus_request_name(conn, "test.method.server",DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
if (dbus_error_is_set(&err)) {fprintf(stderr, "Name Error (%s)\n", err.message);dbus_error_free(&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {exit(1);
}
一般来说,连接上 Dbus 和注册一个名称,应该是在程序最开始运行的时候就会进行的操作。


当然,在程序的结束的时候,需要关闭掉与 Dbus 的连接。使用下面的函数:

dbus_connection_close(conn);

二、发送信号(Sending Signal)
信号是一种广播的消息,你可以简单的发出一个信号,这样,所有连接在 DBus 总线上并注册了接受对应信号的进程,都会收到这个信号。为了发出一个信号,需要的只是创建一个 DBusMessage 对象来代表信号,然后追加上一些需要发出的参数,就可以发向总线了。发完之后还需要释放掉 Message。如果内存不足的话,这下面不少函数都会返回 false,所以一般情况下你都需要处理这些情况的返回值。

dbus_uint32_t serial = 0; // unique number to associate replies with requests
DBusMessage* msg;
DBusMessageIter args;// create a signal and check for errors
msg = dbus_message_new_signal("/test/signal/Object", // object name of the signal"test.signal.Type", // interface name of the signal"Test"); // name of the signal
if (NULL == msg)
{fprintf(stderr, "Message Null\n");exit(1);
}// append arguments onto signal
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) {fprintf(stderr, "Out Of Memory!\n");exit(1);
}// send the message and flush the connection
if (!dbus_connection_send(conn, msg, &serial)) {fprintf(stderr, "Out Of Memory!\n");exit(1);
}
dbus_connection_flush(conn);// free the message
dbus_message_unref(msg);

三、调用方法(Calling a Method)
调用一个远程方法(remote method)与发送一个信号(sending a signal)是很类似的。需要创建一个 DBusMessage,然后通过注册在 DBus 上的名称指定发送的对象。然后追加相应的参数,但调用方法分为两种,一种是阻塞式的,另一种则可以异步调用。异步调用的时候会得到一个 DBusMessage* 的返回,从这个 DBusMessage 中可以获取一些返回的参数。

调用方法1:

DBusMessage* msg;
DBusMessageIter args;
DBusPendingCall* pending;msg = dbus_message_new_method_call("test.method.server", // target for the method call"/test/method/Object", // object to call on"test.method.Type", // interface to call on"Method"); // method name
if (NULL == msg) {fprintf(stderr, "Message Null\n");exit(1);
}// append arguments
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, ¶m)) {fprintf(stderr, "Out Of Memory!\n");exit(1);
}// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeoutfprintf(stderr, "Out Of Memory!\n");exit(1);
}
if (NULL == pending) {fprintf(stderr, "Pending Call Null\n");exit(1);
}
dbus_connection_flush(conn);// free message
dbus_message_unref(msg);
调用方法2:
bool stat;
dbus_uint32_t level;// block until we receive a reply
dbus_pending_call_block(pending);// get the reply message
msg = dbus_pending_call_steal_reply(pending);
if (NULL == msg) {fprintf(stderr, "Reply Null\n");exit(1);
}
// free the pending message handle
dbus_pending_call_unref(pending);// read the parameters
if (!dbus_message_iter_init(msg, &args))fprintf(stderr, "Message has no arguments!\n");
else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))fprintf(stderr, "Argument is not boolean!\n");
elsedbus_message_iter_get_basic(&args, &stat);if (!dbus_message_iter_next(&args))fprintf(stderr, "Message has too few arguments!\n");
else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))fprintf(stderr, "Argument is not int!\n");
elsedbus_message_iter_get_basic(&args, &level);printf("Got Reply: %d, %d\n", stat, level);// free reply and close connection
dbus_message_unref(msg);

四、接收消息(Receiving a Signal)
接下来的两种操作主要是从总线从读取消息并处理这些消息。
要接收一个消息,你首先需要告诉 DBus 你对什么样的消息感兴趣:

// add a rule for which messages we want to see
dbus_bus_add_match(conn,"type='signal',interface='test.signal.Type'",&err); // see signals from the given interface
dbus_connection_flush(conn);
if (dbus_error_is_set(&err)) {fprintf(stderr, "Match Error (%s)\n", err.message);exit(1);
}

然后,进程就可以在一个循环中等待这类消息的发生了:

/ loop listening for signals being emmitted
while (true) {// non blocking read of the next available messagedbus_connection_read_write(conn, 0);msg = dbus_connection_pop_message(conn);// loop again if we haven't read a messageif (NULL == msg) {sleep(1);continue;}// check if the message is a signal from the correct interface and with the correct nameif (dbus_message_is_signal(msg, "test.signal.Type", "Test")) {// read the parametersif (!dbus_message_iter_init(msg, &args))fprintf(stderr, "Message has no arguments!\n");else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))fprintf(stderr, "Argument is not string!\n");else {dbus_message_iter_get_basic(&args, &sigvalue);printf("Got Signal with value %s\n", sigvalue);}}// free the messagedbus_message_unref(msg);
}

五、提供被远程调用的方法(Exposing a Method to be called)
在第二节中,我们看到了调用一个远程方法,这节就是告诉我们怎么样提供一个方法让别的应用程序调用。用下面的程序,就可以把方法关联在那些提供给外部的方法上,并解析出相应的参数,最后构建一个消息返回给调用方法的应用程序。

提供被远程调用的方法1:

// loop, testing for new messages
while (true) {// non blocking read of the next available messagedbus_connection_read_write(conn, 0);msg = dbus_connection_pop_message(conn);// loop again if we haven't got a messageif (NULL == msg) {sleep(1);continue;}// check this is a method call for the right interface and methodif (dbus_message_is_method_call(msg, "test.method.Type", "Method"))reply_to_method_call(msg, conn);// free the messagedbus_message_unref(msg);
}
提供被远程调用的方法2:
void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
{DBusMessage* reply;DBusMessageIter args;DBusConnection* conn;bool stat = true;dbus_uint32_t level = 21614;dbus_uint32_t serial = 0;char* param = "";// read the argumentsif (!dbus_message_iter_init(msg, &args))fprintf(stderr, "Message has no arguments!\n");else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))fprintf(stderr, "Argument is not string!\n");elsedbus_message_iter_get_basic(&args, ¶m);printf("Method called with %s\n", param);// create a reply from the messagereply = dbus_message_new_method_return(msg);// add the arguments to the replydbus_message_iter_init_append(reply, &args);if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) {fprintf(stderr, "Out Of Memory!\n");exit(1);}if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) {fprintf(stderr, "Out Of Memory!\n");exit(1);}// send the reply && flush the connectionif (!dbus_connection_send(conn, reply, &serial)) {fprintf(stderr, "Out Of Memory!\n");exit(1);}dbus_connection_flush(conn);// free the replydbus_message_unref(reply);
}

这就基本上全部了。但用这些来理解 DBus 显然还远远不够。接下来,就要对这些程序以及背后的理念进行具体的探究了。

转载自:http://www.cnblogs.com/liyiwen/archive/2012/12/02/2798876.html

参考资料:

  1. http://dbus.freedesktop.org/doc/dbus-specification.html  这当然是最权威最重要的资料,但我觉得不是一个很好的入门资料。
  2. http://dbus.freedesktop.org/doc/dbus-tutorial.html 这里面有一些不错的例子,对Names 的解释也很好,但用的是 glib 的 binding,不能探究更底层的动作一度还是让我云里雾里。
  3. http://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html  DBus 的 C 编程接口的在线文档,非常棒也非常有用

这篇关于dbus的入门于应用--dbus的C编程接口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题: