基于GDbus与QDbus的DBUS小练习

QDbus

API:QT 的帮助文档
任务描述:
proxy 获取 adaptor的数据,修改数据,接收数据修改的信号并查看新的值。
文件结构:

➜ DbusTest git:(master) ✗ tree
.
├── Adaptor
│ ├── Adaptor.pro
│ ├── Makefile
│ ├── OrgExampleDdbusTest.xml
│ ├── main.cpp
│ ├── orgexampleddbustest_adaptor.cpp
│ ├── orgexampleddbustest_adaptor.h
│ ├── testadaptor.cpp
│ └── testadaptor.h
├── DbusTest.pro
├── DbusTest.pro.user
└── Proxy
    ├── Makefile
    ├── OrgExampleDdbusTest.xml
    ├── Proxy.pro
    ├── main.cpp
    ├── orgexampleddbustest_interface.cpp
    ├── orgexampleddbustest_interface.h
    ├── testproxy.cpp
    └── testproxy.h

接口文件 XML:

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
        "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/examples/qdbus/wtest">
        <interface name="org.example.qdbus.wtest">
                <signal name="valueChanged">
                    <arg name="newValue" type="d" direction="out"/>
                </signal>
                <method name="setValue">
                    <arg name="newValue" type="d" direction="in"/>
                </method>
                <method name="getValue" type="d" direction="out"/>
        </interface>
</node>

依据XML生成源码的工具:qdbusxml2cpp
远端的函数返回值不能传递到client,但我们可以通过信号来传递server的value到client。

执行效果:

➜ Proxy git:(master) ✗ ./Proxy.app/Contents/MacOS/Proxy
original value: 0
onValueChanged, interface get value: 20

➜ Adaptor git:(master) ✗ ./Adaptor.app/Contents/MacOS/Adaptor
has error ? QDBusError("", "")
TestAdaptor::getValue 12
TestAdaptor::setValue 20

之所以能在server发送signal,让client作出响应,是因为WtestAdaptor和OrgExampleQdbusWtestInterface在构造函数中均有这样的设置:
setAutoRelaySignals(true);
这样的话,可以在parent也就是server进程类中直接emit,进程间的信号转发就交给WtestAdaptor处理了。

// Adaptor/orgexampleddbustest_adaptor.h
/*
 * Adaptor class for interface org.example.qdbus.wtest
 */
class WtestAdaptor: public QDBusAbstractAdaptor
{
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "org.example.qdbus.wtest")
...

// Proxy/orgexampleddbustest_interface.h
/*
 * Proxy class for interface org.example.qdbus.wtest
 */
class OrgExampleQdbusWtestInterface: public QDBusAbstractInterface
{
    Q_OBJECT
public:
    static inline const char *staticInterfaceName()
    { return "org.example.qdbus.wtest"; }
...

工程地址:https://github.com/theArcticOcean/qtLib/tree/master/DbusTest

2018.6.23更新:上面的XML getValue写法有误,所以,不能传递到client。修正:

<method name= "getValue">
 <arg type="d" name="aResult" direction="out" />
</method>

关于arg type的写法:double对应d,bool对应b,int对应i,unit对应u ……

GDbus

API:https://developer.gnome.org/gio/stable/gdbus-convenience.html
依据XML生成源码的工具:gdbus-codegen
还是使用QtDbus例子中的OrgExampleDdbusTest.xml。
相关命令:gdbus-codegen –generate-c-code=DbusTest_code OrgExampleDdbusTest.xml
然后,相关的文件DbusTest_code.h和DbusTest_code.c便生成了。
目录结构 (本工程使用waf工具进行编译):

➜ DbusTest git:(local) ✗ tree
.
├── Client
│ ├── GDbusClient.c
│ └── wscript
├── DbusTest_code.c
├── DbusTest_code.h
├── OrgExampleDdbusTest.xml
├── Server
│ ├── GDbusServer.c
│ └── wscript
├── waf
└── wscript

DbusTest_code.h的部分内容:

struct _OrgExampleQdbusWtestIface
{
  GTypeInterface parent_iface;

  gboolean (*handle_get_value) (
    OrgExampleQdbusWtest *object,
    GDBusMethodInvocation *invocation);

  gboolean (*handle_set_value) (
    OrgExampleQdbusWtest *object,
    GDBusMethodInvocation *invocation,
    gdouble arg_newValue);

  void (*value_changed) (
    OrgExampleQdbusWtest *object,
    gdouble arg_newValue);
};
//...
/* D-Bus signal emissions functions: */
void org_example_qdbus_wtest_emit_value_changed (
    OrgExampleQdbusWtest *object,
    gdouble arg_newValue);

/* D-Bus method calls: */
void org_example_qdbus_wtest_call_set_value (
    OrgExampleQdbusWtest *proxy,
    gdouble arg_newValue,
    GCancellable *cancellable,
    GAsyncReadyCallback callback,
    gpointer user_data);

gboolean org_example_qdbus_wtest_call_set_value_finish (
    OrgExampleQdbusWtest *proxy,
    GAsyncResult *res,
    GError **error);

gboolean org_example_qdbus_wtest_call_set_value_sync (
    OrgExampleQdbusWtest *proxy,
    gdouble arg_newValue,
    GCancellable *cancellable,
    GError **error);
//...
OrgExampleQdbusWtest *org_example_qdbus_wtest_proxy_new_for_bus_sync (
    GBusType bus_type,
    GDBusProxyFlags flags,
    const gchar *name,
    const gchar *object_path,
    GCancellable *cancellable,
    GError **error);
//...
OrgExampleQdbusWtest *org_example_qdbus_wtest_skeleton_new (void);

Client/GDbusClient.c 关键内容:

static gboolean onValueChanged
    (
    OrgExampleQdbusWtest *object,
    double newValue,
    gpointer user_data
    )
{
    g_print( "onValueChanged, get value: %lf\n", newValue );
    return TRUE;
}

int main( int argc, char *argv[] )
{
    //...
    proxy = org_example_qdbus_wtest_proxy_new_for_bus_sync(
            G_BUS_TYPE_SESSION,
            G_DBUS_PROXY_FLAGS_NONE,
            "org.example.qdbus.wtest",
            "/com/examples/qdbus/wtest",
            NULL,
            &error );
    if( NULL == proxy )
    {
        g_print( "proxy init failed: %s", error->message );
        exit( 0 );
    }
    // connect step
    g_signal_connect( proxy, "value-changed", G_CALLBACK( onValueChanged ), NULL );

    // set new value.
    org_example_qdbus_wtest_call_set_value_sync( proxy, 20, NULL, &error );
    g_main_loop_run( loop );
    // ... 
}

Server/GDbusServer.c 关键内容:

// Callback function on_handle_set_value has form
// which is deined in struct _OrgExampleQdbusWtestIface
static gboolean on_handle_set_value
    (
    OrgExampleQdbusWtest *object,
    GDBusMethodInvocation *invocation,
    gdouble arg_newValue
    )
{
    g_print( "on_handle_set_value, set value: %lf\n", arg_newValue );
    iPrivate.data = arg_newValue;
    org_example_qdbus_wtest_complete_set_value( object, invocation );
    org_example_qdbus_wtest_emit_value_changed( object, arg_newValue );
    return TRUE;
}

static void GBusAcquired_Callback
    (
    GDBusConnection *connection,
    const gchar *name,
    gpointer user_data
    )
{
    GError *error = NULL;
    g_print( "GBusAcquired_Callback, name is %s, user_data: %s\n", name, (char *)user_data );
    adaptor = org_example_qdbus_wtest_skeleton_new();
    // connect step
    g_signal_connect( adaptor, "handle-set-value", G_CALLBACK( on_handle_set_value ), NULL );
    g_dbus_interface_skeleton_export( G_DBUS_INTERFACE_SKELETON( adaptor ), connection, "/com/examples/qdbus/wtest", &error );
    if( NULL != error )
    {
        g_print( "Failed to export object: %s\n", error->message );
        g_error_free( error );
    }
}
//...
int main()
{
    GMainLoop* loop = NULL;
    guint own_id = g_bus_own_name(
                    G_BUS_TYPE_SESSION,
                    "org.example.qdbus.wtest",
                    G_BUS_NAME_OWNER_FLAGS_NONE,
                    GBusAcquired_Callback,
                    GBusNameAcquired_Callback,
                    GBusNameLost_Callback,
                    NULL,
                    NULL
                    );

    loop = g_main_loop_new( NULL, FALSE );
    g_main_loop_run( loop );

    g_bus_unown_name( own_id );
    return 0;
}

其中on_handle_set_value就是服务端的setValue函数,客户端调用org_example_qdbus_wtest_call_set_value_sync触发此函数的执行,在他设置新的value后也发送了信号通知客户端 org_example_qdbus_wtest_emit_value_changed
不知为啥,本工程在mac上总是连不上dbus,重启dbus守护进程也报错:

dbus-daemon --config-file=/usr/local/Cellar/dbus/1.12.8/share/dbus-1/session.conf --print-address
dbus-daemon[34918]: Failed to start message bus: Check-in failed: No such process

然后,我就到Ubuntu上尝试了一波。可以的。
server
client
工程地址:https://github.com/theArcticOcean/CLib/tree/master/DbusTest

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/theArcticOcean/article/details/80720429
文章标签: DBUS IPC LINUX
上一篇waf 编译入门小练习
下一篇QT开发GIF截屏工具的问题记录
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭