dbus的hello world

78 篇文章 0 订阅
15 篇文章 0 订阅
DBus 是一种低延迟、低开销、高可用性的进程间通信(IPC)机制。本文通过一个简单的Hello World示例,介绍如何使用DBus进行信号发送和跨进程函数调用。客户端发送信号,服务端接收,涉及创建会话连接、设置消息回调、添加匹配规则等步骤;服务端则需要设置名称以便通信,并进入消息处理循环。同时,也概述了客户端如何发起跨进程调用。
摘要由CSDN通过智能技术生成

来自:http://blog.csdn.net/chenyufei1013/article/details/6573411 

dbus的是一个低延迟,低开销,高可用性的IPC机制。通过dbus的daemon,可以实现进程间通信和函数调用。Windows下,dbus的开发库可以去这里(http://code.google.com/p/dbus-windows-installer/downloads/list)下载,在VS设置头文件和lib库的路径即可。若是要编写其Hello World,自然包含客户端和服务端两部分。下面的Hello World代码包含了发送消息和函数调用两部分,分别描述之。

      1) 信号

假设客户端发送消息,服务端接收。客户端发送消息的流程如下: 
1.创建于dbus daemon的会话连接。 
2.创建消息,若有消息参数,附加之(这个一般都有) 
3.通过连接发送消息。

   1: int main (int argc, char *argv[])
   2: {
   3:     DBusError dberr;
   4:     DBusConnection *dbconn;
   5:     DBusMessage *dbmsg;
   6:     char *text;
   7:  
   8:     // 初始话错误信息的结构体
   9:     dbus_error_init (&dberr);
  10:     
  11:     // 创建会话连接
  12:     dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  
  13:     if (dbus_error_is_set (&dberr)) {
  14:         fprintf (stderr, "getting session bus failed: %s/n", dberr.message);
  15:         dbus_error_free (&dberr);
  16:         return EXIT_FAILURE;
  17:     }
  18:  
  19:     // 创建消息
  20:     dbmsg = dbus_message_new_signal ("/com/wiley/test",
  21:                                      "com.wiley.test",
  22:                                      "TestSignal");
  23:     if (!dbmsg) {
  24:         fprintf (stderr, "Could not create a new signal/n");
  25:         return EXIT_FAILURE;
  26:     }
  27:  
  28:     // 消息中,附加文本
  29:     text = "Hello World";
  30:     if (!dbus_message_append_args (
  31:         dbmsg, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) {
  32:         fprintf(stderr, "Out Of Memory!/n"); 
  33:         return EXIT_FAILURE;
  34:     }
  35:  
  36:     // 发送消息
  37:     if (!dbus_connection_send (dbconn, dbmsg, NULL)) {
  38:         fprintf(stderr, "Out Of Memory!/n"); 
  39:         return EXIT_FAILURE;
  40:     }
  41:     dbus_connection_flush(dbconn);
  42:  
  43:     printf ("Sending signal to D-Bus/n");
  44:  
  45:     // 释放消息
  46:     dbus_message_unref (dbmsg);
  47:  
  48:     // 释放会话连接
  49:     dbus_connection_unref (dbconn);
  50:  
  51:     return EXIT_SUCCESS;
  52: }

服务端接收消息的流程如下: 
1.创建于dbus daemon的会话连接。 
2.为本次连接设置名称,客户端可以通过此名称进行通信 
3.设置消息对应的回调函数 
4.添加消息匹配规则 
5.进入处理消息的循环

   1: static DBusHandlerResult
   2: filter_func (DBusConnection *connection,
   3:              DBusMessage *message,
   4:              void *user_data)
   5: {
   6:     dbus_bool_t handled = FALSE;
   7:     char *signal_text = NULL;
   8:  
   9:     // 若为指定信号
  10:     if (dbus_message_is_signal (message, "com.wiley.test", "TestSignal")) {
  11:         DBusError dberr;
  12:         // 初始化错误结构体
  13:         dbus_error_init (&dberr);
  14:         // 获取消息的参数
  15:         dbus_message_get_args (message, &dberr, DBUS_TYPE_STRING, &signal_text, DBUS_TYPE_INVALID);
  16:         if (dbus_error_is_set (&dberr)) {
  17:             fprintf (stderr, "Error getting message args: %s", dberr.message);
  18:             dbus_error_free (&dberr);
  19:         } else {
  20:             printf ("Received TestSignal with value of: '%s'/n", signal_text);
  21:             // 标识本消息已处理
  22:             handled = TRUE;
  23:         }
  24:     }
  25:     // 返回值决定该消息是否处理
  26:     return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
  27: }
  28:  
  29:  
  30: int main (int argc, char *argv[])
  31: {
  32:     DBusError dberr;
  33:     DBusConnection *dbconn;
  34:  
  35:     // 初始话错误信息的结构体
  36:     dbus_error_init (&dberr);
  37:     
  38:     // 创建会话
  39:     dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);
  40:     if (dbus_error_is_set (&dberr)) {
  41:         fprintf (stderr, "getting session bus failed: %s/n", dberr.message);
  42:         dbus_error_free (&dberr);
  43:         return EXIT_FAILURE;
  44:     }
  45:  
  46:     // 向daemon追加了一条路由到该应用程序入口
  47:     dbus_bus_request_name (dbconn, "com.wiley.test",
  48:                            DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);
  49:     if (dbus_error_is_set (&dberr)) {
  50:         fprintf (stderr, "requesting name failed: %s/n", dberr.message);
  51:         dbus_error_free (&dberr);
  52:         return EXIT_FAILURE;
  53:     }
  54:  
  55:     // 设置处理消息的函数
  56:     if (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL)) {
  57:         return EXIT_FAILURE;
  58:     }
  59:  
  60:     // 添加消息匹配规则
  61:     dbus_bus_add_match (dbconn,
  62:                         "type='signal',interface='com.wiley.test'",
  63:                         &dberr);
  64:     if (dbus_error_is_set (&dberr)) {
  65:         fprintf (stderr, "Could not match: %s", dberr.message);
  66:         dbus_error_free (&dberr);
  67:         return EXIT_FAILURE;
  68:     }
  69:  
  70:     // 分派消息的Loop
  71:     while (dbus_connection_read_write_dispatch (dbconn, -1))
  72:         ; /* empty loop body */
  73:  
  74:     return EXIT_SUCCESS;
  75: }

      2) 跨进程调用 

跨进程调用中,客户端和服务端的流程差不多,假设客户端跨进程调用服务端函数。 
客户端

   1: int main (int argc, char *argv[])
   2: {
   3:     DBusMessage* msg;
   4:     DBusMessageIter args;
   5:     DBusConnection* conn;
   6:     DBusError err;
   7:     DBusPendingCall* pending;
   8:     char* param = "no param";
   9:     int ret;
  10:     dbus_bool_t stat = FALSE;
  11:     dbus_uint32_t level = 0;
  12:  
  13:     printf("Calling remote method with %s/n", param);
  14:  
  15:     // 初始化错误
  16:     dbus_error_init(&err);
  17:  
  18:     // 获取会话连接
  19:     conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
  20:     if (dbus_error_is_set(&err)) { 
  21:         fprintf(stderr, "Connection Error (%s)/n", err.message); 
  22:         dbus_error_free(&err);
  23:     }
  24:     if (NULL == conn) { 
  25:         exit(1); 
  26:     }
  27:  
  28:     // 设置连接名称,若存在则替换
  29:     ret = dbus_bus_request_name(conn, "test.method.caller", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
  30:     if (dbus_error_is_set(&err)) { 
  31:         fprintf(stderr, "Name Error (%s)/n", err.message); 
  32:         dbus_error_free(&err);
  33:     }
  34:     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
  35:         exit(1);
  36:     }
  37:  
  38:     // 创建方法调用的消息
  39:     msg = dbus_message_new_method_call("com.test.dbus.server",    // target for the method call
  40:                                        "/test/method/Object",    // object to call on
  41:                                        "test.method.Interface", // interface to call on
  42:                                        "Method");                // method name
  43:     if (NULL == msg) { 
  44:         fprintf(stderr, "Message Null/n");
  45:         exit(1);
  46:     }
  47:  
  48:     // 附加参数
  49:     dbus_message_iter_init_append(msg, &args);
  50:     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
  51:         fprintf(stderr, "Out Of Memory!/n"); 
  52:         exit(1);
  53:     }
  54:  
  55:     // 发送消息(-1表示使用默认超时)
  56:     if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) {
  57:         fprintf(stderr, "Out Of Memory!/n"); 
  58:         exit(1);
  59:     }
  60:     if (NULL == pending) { 
  61:         fprintf(stderr, "Pending Call Null/n"); 
  62:         exit(1); 
  63:     }
  64:  
  65:     // 阻塞直到发送的消息队列为空
  66:     dbus_connection_flush(conn);
  67:  
  68:     printf("Request Sent/n");
  69:  
  70:     // 释放消息
  71:     dbus_message_unref(msg);
  72:  
  73:     // 阻塞至消息返回
  74:     dbus_pending_call_block(pending);
  75:  
  76:     // 获取返回消息
  77:     msg = dbus_pending_call_steal_reply(pending);
  78:     if (NULL == msg) {
  79:         fprintf(stderr, "Reply Null/n"); 
  80:         exit(1); 
  81:     }
  82:     
  83:     // 释放pending
  84:     dbus_pending_call_unref(pending);
  85:  
  86:     // 读取参数
  87:     if (!dbus_message_iter_init(msg, &args))
  88:         fprintf(stderr, "Message has no arguments!/n"); 
  89:     else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args)) 
  90:         fprintf(stderr, "Argument is not boolean!/n"); 
  91:     else
  92:         dbus_message_iter_get_basic(&args, &stat);
  93:  
  94:     if (!dbus_message_iter_next(&args))
  95:         fprintf(stderr, "Message has too few arguments!/n"); 
  96:     else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) 
  97:         fprintf(stderr, "Argument is not int!/n"); 
  98:     else
  99:         dbus_message_iter_get_basic(&args, &level);
 100:  
 101:     printf("Got Reply: %d, %d/n", stat, level);
 102:  
 103:     // 释放方法返回的消息
 104:     dbus_message_unref(msg);  
 105:  
 106:     return EXIT_SUCCESS;
 107: }

服务端

   1: static
   2: void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
   3: {
   4:     DBusMessage* reply;
   5:     DBusMessageIter args;
   6:     dbus_bool_t stat = TRUE;
   7:     dbus_uint32_t level = 21614;
   8:     dbus_uint32_t serial = 0;
   9:     char* param = "";
  10:  
  11:     // 读取参数
  12:     if (!dbus_message_iter_init(msg, &args)) // 获取参数
  13:         fprintf(stderr, "Message has no arguments!/n"); 
  14:     else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) // 参数类型不为字符串
  15:         fprintf(stderr, "Argument is not string!/n"); 
  16:     else { // 参数为字符串
  17:         dbus_message_iter_get_basic(&args, &param);
  18:     }
  19:  
  20:     printf("Method called with %s/n", param);
  21:  
  22:     // 创建返回类型的消息,对应于调用的消息
  23:     reply = dbus_message_new_method_return(msg);
  24:  
  25:     // 初始化返回的参数
  26:     dbus_message_iter_init_append(reply, &args);
  27:     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) { // 附加基本类型的值到消息中
  28:         fprintf(stderr, "Out Of Memory!/n"); 
  29:         exit(1);
  30:     }
  31:     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) { // 附加基本类型的值到消息中
  32:         fprintf(stderr, "Out Of Memory!/n"); 
  33:         exit(1);
  34:     }
  35:  
  36:     // 发送返回消息
  37:     if (!dbus_connection_send(conn, reply, &serial)) {
  38:         fprintf(stderr, "Out Of Memory!/n"); 
  39:         exit(1);
  40:     }
  41:     dbus_connection_flush(conn);
  42:  
  43:     // 释放方法返回的消息
  44:     dbus_message_unref(reply);
  45: }
  46:  
  47: int main (int argc, char *argv[])
  48: {
  49:     DBusError dberr;
  50:     DBusConnection * dbconn;
  51:     DBusMessage * msg;
  52:     int ret;
  53:  
  54:     // 初始话错误信息的结构体
  55:     dbus_error_init (&dberr);
  56:     // 创建会话
  57:     dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);
  58:     if (dbus_error_is_set (&dberr)) {
  59:         fprintf (stderr, "getting session bus failed: %s/n", dberr.message);
  60:         dbus_error_free (&dberr);
  61:         return EXIT_FAILURE;
  62:     }
  63:  
  64:     // 为本次连接设置名称,客户端可以通过此名称进行通信
  65:     ret = dbus_bus_request_name (dbconn, "com.test.dbus.server",
  66:                            DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);
  67:     if (dbus_error_is_set (&dberr)) {
  68:         fprintf (stderr, "requesting name failed: %s/n", dberr.message);
  69:         dbus_error_free (&dberr);
  70:         return EXIT_FAILURE;
  71:     }
  72:     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
  73:         fprintf(stderr, "Not Primary Owner (%d)/n", ret);
  74:         exit(1); 
  75:     }
  76:  
  77:     // 循环等待消息
  78:     while (true) {
  79:         // 非阻塞的获取下一个消息
  80:         // TODO: 如何阻塞?
  81:         dbus_connection_read_write(dbconn, 0);
  82:  
  83:         // 获取消息
  84:         msg = dbus_connection_pop_message(dbconn);
  85:         if (NULL == msg) { 
  86:             // sleep(1);
  87:             continue; 
  88:         }
  89:  
  90:         // 相应消息调用
  91:         if (dbus_message_is_method_call(msg, "test.method.Interface", "Method")) 
  92:             reply_to_method_call(msg, dbconn);
  93:  
  94:         // 释放引用
  95:         dbus_message_unref(msg);
  96:     }
  97:  
  98:     return EXIT_SUCCESS;
  99: }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值