OPENWRT 教程第十二章 dbus 高级进程间通信

D-Bus : 是一个为应用程序间通信的消息总线系统, 用于进程之间的通信。

相较于传统的 管道(PIPE) 、 Socket 等原生基于字节流的IPC方式, D-Bus 提供了基于独立 Message 的传输方式,应用程序使用起来更加简单。

想一下传统进程间通信方式及用法?

D-Bus 的常用架构与传统的 Socket 一对一通信模式不同,它基于中间消息路由转发的模式来实现, 如下图:

D-Bus 默认提供两种BUS:系统BUS(system) 和 会话BUS(session) 

系统BUS在每台机器上是惟一的,用于后台服务及操作系统之间的通信。

会话BUS用于每个登录用户会话的应用程序之间的通信。每个BUS实例由一个 bus-daemon 进程来管理,由其负责消息路由转发。应用程序需要收发消息,需要连接到BUS实例上。BUS实例使用基于XML的配置文件来控制安全策略,如用户能否注册服务,能给哪些服务接口发送消息等等。

下面我们用一个基于 libdbus 库实现的示例来说明简单的方法调用。

libdbus 官方API 参考链接 : https://dbus.freedesktop.org/doc/api/html/group__DBusBus.html

/*
dbus_open : 建立一个dbus连接之后,为这个dbus连接起名
    svrname : 客户端请求注册的名称
*/
int dbus_open(const char * svrname)
{
    DBusConnection* conn;
    DBusError err;
    int ret;

    /*
    DBUS_EXPORT void dbus_connection_set_change_sigpipe(dbus_bool_t will_modify_sigpipe)
        此函数用于设置dbus_connection_new()是否将sigpippe behavior设置为SIG_IGN的全局标志。
        TRUE以允许将sigpipe设置为SIG
        FALSE以禁止将sigpipe设置为SIG
    */
    dbus_connection_set_change_sigpipe(FALSE);
    
    /*DBUS_EXPORT void dbus_error_init(DBusError *     error)
        初始化 DBusError结构体,不分配任何内存;仅当错误在某个点设置时才需要释放它。
    */
    dbus_error_init(&err);
    //conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
    
    /*
    DBUS_EXPORT DBusConnection * dbus_bus_get(DBusBusType type,DBusError *     error)    
        连接到总线守护程序,并向其注册客户端。
        Parameters
            type    bus 类型,这边是DBUS_BUS_SYSTEM :系统BUS
            error    返回错误的地址.
        Returns
            a DBusConnection with new ref or NULL on error
    */
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    if (dbus_error_is_set(&err))//检查是否发生错误(已设置错误)。
    {
        fprintf (stderr, "%s: Connection Error (%s)\n", __FUNCTION__, err.message);
        dbus_error_free(&err);
        conn = NULL;
    }
    if(conn == NULL)
    {
        return (int)NULL;
    }

    if(svrname != NULL)
    {
        if(svrname[0] != '\0')
        {
            /*DBUS_EXPORT int dbus_bus_request_name (DBusConnection * connection, const char * name, unsigned int flags, DBusError * error )    
                请求总线通过调用总线上的 request_name 方法将给定名称分配给此连接。
            */
            ret = dbus_bus_request_name(conn, svrname, DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
            if (dbus_error_is_set(&err))
            {
                fprintf (stderr, "%s: Request Name(%s) Error (%s)\n", __FUNCTION__, svrname, err.message);
                dbus_error_free(&err);
                return (int)NULL;
            }

            /*返回 DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 时 , 表示 该名称未被注册可以使用*/
            if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
            {
                fprintf (stderr, "%s: The primary owner is not me\n", __FUNCTION__);
                return (int)NULL;
            }
        }
    }
    return (int)conn;
}
/*
第一步 :建立一个dbus连接之后,为这个dbus连接起名,

第二步 :为我们将要进行的消息循环添加匹配条件
(就是通过信号名和信号接口名来进行匹配控制的) -- dbus_bus_add_match()。

我们进入等待循环后,只需要对信号名,信号接口名进行判断就可以分别处理各种信号了。在各个处理分支上。我们可以分离出消息中的参数。对参数类型进行判断和其他的处理。
*/
int dbus_setup_interface(int did, const char * path, const char * inf)
{
    DBusConnection* conn;
    DBusError err;
    char rule[DBUS_MAXIMUM_NAME_LENGTH + DBUS_MAXIMUM_NAME_LENGTH + 64];
    int inf_len = 0;
    int path_len = 0;

    conn = (DBusConnection*)did;
    if(conn == NULL || (inf == NULL && path == NULL))
    {
        return -1;
    }
    
    if(inf != NULL)
    {
        inf_len = strlen(inf);
    }
    if(path != NULL)
    {
        path_len = strlen(path);
    }
    
    if((inf_len == 0 && path_len == 0)
        || inf_len > DBUS_MAXIMUM_NAME_LENGTH || path_len > DBUS_MAXIMUM_NAME_LENGTH)
    {
        return -1;
    }
    else if(inf_len != 0 && path_len == 0)
    {
        sprintf(rule, "interface='%s'", inf);
    }
    else if(inf_len == 0 && path_len != 0)
    {
        sprintf(rule, "path='%s'", path);
    }
    else
    {
        sprintf(rule, "interface='%s',path='%s'", inf, path);
    }

    dbus_error_init(&err);
    
    /*DBUS_EXPORT void dbus_bus_add_match(DBusConnection * connection, const char * rule, DBusError* error)    
        :为我们将要进行的消息循环添加匹配条件
        Parameters
            connection    connection to the message bus
            rule    textual form of match rule
            error    location to store any errors

        */
    dbus_bus_add_match(conn, rule, &err);
    
    /*如果执行dbus_connection_flush()函数,那么进程将被阻塞,直到发送队列中的消息被通过SOCKET完全传送出去;如果不执行该函数,则会在下次主循环执行dbus_watch_handle的时候被通过SOCKET传送出去。*/
    dbus_connection_flush(conn);

    if (dbus_error_is_set(&err))
    {
        fprintf (stderr, "%s: Match Error (%s)\n", __FUNCTION__, err.message);
        return -1;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/vx-cg248805770/p/11773258.html