当前位置: 首页 > article >正文

新手向-C接口调用dbus

工作需要用c接口调用dbus,在这里写篇博客记录一下。


1. 方案比较

用C接口调用dbus一般来说有3种方案,分别是libdbusGDBus(GIO的一部分)和sd-bus(systemd的一部分),以下比较了3种方案的优劣:

接口方案libdbusGDBussd-bus
api类型低层 C APIGLib 的高层封装系统级 C API
依赖关系需要dbus需要glib需要systemd
易用性复杂简单较简单
性能有少量开销

之前一直用的libdbus,不过太复杂了,维护成本高。

这次是在linux上使用,系统自带systemd,因此这次选择了sd-bus,简单且不需要额外的依赖。

2. sd-bus的使用

2.1 安装

sudo apt update
sudo apt install libsystemd-dev

2.2  Demo

// sd-bus的头文件
#include <systemd/sd-bus.h>   
#include <stdio.h>

int main(int argc, char *argv[]) {
    sd_bus *bus = NULL;
    sd_bus_message *msg = NULL;
    sd_bus_error error = SD_BUS_ERROR_NULL;
    int ret;

    // 连接到system bus用sd_bus_open_system
    // session bus的话用sd_bus_open_user
    ret = sd_bus_open_system(&bus);
    if (ret < 0) {
        fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-ret));
        return ret;
    }

    // 调用Reboot方法
    ret = sd_bus_call_method(bus,
                             "org.freedesktop.login1",         // Service to contact
                             "/org/freedesktop/login1",        // Object path
                             "org.freedesktop.login1.Manager", // Interface name
                             "Reboot",                         // Method to call
                             &error,                             // No reply expected
                             &msg,                             // Output message
                             NULL);                            // No input arguments
    if (ret < 0) {
        fprintf(stderr, "Failed to call method: %s\n", strerror(-ret));
        sd_bus_unref(bus);
        return ret;
    }

    // 检查返回值
    int response = 0;
    // 假如返回值是int类型
    ret = sd_bus_message_read(msg, "i", &response); 
    if (ret < 0) {
        fprintf(stderr, "Failed to read response: %s\n", strerror(-ret));
    } else {
        printf("Method returned response: %d\n", response);
    }


    // Cleanup
    sd_bus_message_unref(msg);
    sd_bus_unref(bus);

    return 0;
}

 简单介绍一下,使用sd-bus的核心接口只有3个,连接到总线,调用method,以及读取返回值

2.2.1 连接到总线

连接到总线的接口有3个,函数原型如下:

int sd_bus_open_system(sd_bus **ret);             
// 连接system bus
int sd_bus_open_user(sd_bus **ret);               
// 连接session bus
int sd_bus_default(sd_bus **ret);                 
// 先连接session bus,不可用再连接system bus
2.2.2 调用method

函数原型如下:

// sd_bus_call_method 函数原型
int sd_bus_call_method(
    sd_bus *bus,                  // 总线连接
    const char *destination,      // 目标服务名
    const char *path,             // 对象路径
    const char *interface,        // 接口名称
    const char *member,           // 方法名
    sd_bus_error *ret_error,      // 错误信息
    sd_bus_message **reply,       // 响应消息
    const char *types,            // 参数类型字符串
    ...                          // 可变参数列表
);

调用带多个参数的method

// 调用带多个参数的method
ret = sd_bus_call_method(bus,
                         "org.example.Service",
                         "/org/example/object",
                         "org.example.Interface",
                         "ComplexMethod",
                         &error,
                         &reply,
                         "siay",          // string, int32, array of bytes
                         "test",          // string参数
                         42,              // int32参数
                         3,               // 数组长度
                         (uint8_t[]){1,2,3}); // byte数组

/* 常用参数类型说明:
 * s: string (const char *)
 * u: uint32_t
 * i: int32_t
 * x: int64_t
 * t: uint64_t
 * b: boolean (int)
 * y: byte (uint8_t)
 * d: double
 * ay: array of bytes
 * as: array of strings
 * a{sv}: dictionary of string keys to variant values
 * v: variant
 * o: object path
 */

调用带一个参数的method

    // 调用带参数的方法
    ret = sd_bus_call_method(bus,
                           "org.freedesktop.systemd1",           // 服务
                           "/org/freedesktop/systemd1",          // 路径
                           "org.freedesktop.systemd1.Manager",   // 接口
                           "GetUnit",                            // 方法
                           &error,                               // 错误对象
                           &reply,                               // 响应消息
                           "s",                                  // 参数类型: 字符串
                           "sshd.service");                      // 参数值
2.2.3 读取返回值

函数原型如下,第一个入参是调用method,引用传递返回的reply。

// sd_bus_message_read 函数原型
int sd_bus_message_read(
    sd_bus_message *m,    // 消息对象
    const char *types,    // 数据类型字符串
    ...                   // 要读取的变量指针
);

读取多个返回值的示例如下:

int ret;
const char *str;
int32_t num;
uint8_t byte;
double dbl;
    
// 读取基本类型:字符串、32位整数、字节、双精度浮点数
ret = sd_bus_message_read(m, "siyd",
                          &str,    // 字符串
                          &num,    // 32位整数
                          &byte,   // 字节
                          &dbl);   // 双精度浮点数

http://www.kler.cn/news/364358.html

相关文章:

  • ctfshow(41)--RCE/命令执行漏洞--或绕过
  • FreeRTOS代码规范(3)
  • 反编译工具jadx
  • 【Qt6聊天室项目】 主界面功能实现
  • 2024年10月24日随笔
  • Vue弹窗用也可以直接调用Js方法了
  • 软件部署-Docker容器化技术(二)
  • (清晰易懂版)(multi)map和set--C++
  • 数据结构~红黑树
  • Linux基础环境搭建(CentOS7)- 安装Scala和Spark
  • webassembly之typescript支持
  • OpenCV系列教程五:图像的分割与修复
  • 代谢组数据分析(二十):通过WGCNA识别核心代谢物
  • 面向对象进阶(下)(JAVA笔记第二十二期)
  • 数据结构(8.2_2)—希尔排序
  • 了解 WebSocket
  • 【格物刊】龙信刊物已上新
  • 【linux开发-驱动】SPI驱动开发相关
  • node和npm
  • 指增和中性产品的申赎加减仓及资金调拨自动化伪代码思路
  • 【数据仓库】数据仓库面试题
  • ANSI C、ISO C、POSIX标准、GNU的含义
  • 【机器学习】多元线性回归
  • python回调函数概念及应用场景举例
  • AD画的原理图如何导出PDF
  • 如何使用DBeaver连接flink