DBus 服务器端接收方式
DBus 服务器端用来接收signal和method调用。从收集的资料中发现,主要有三种接收方式。
一,采用while循环,监听dbus_connection_read_write()函数。有消息到来时在循环内部进行处理。优点是结构简单,处理方便。程序结构如下图。
/*
test.signal.server(bus name)|----test.signal.Type(interface1)| || ----FunctionOne(method1)| || ----FunctionTwo(method2)----org.freedesktop.DBus.Introspectable(interface3)| || ----Introspect(method3)response to interface(test.signal.Type) signal(Test)
response to interface(test.signal.Type2) signal(TestString)
response to interface(test.signal.Type) signal(MulType)
*/
#include <iostream>
#include <stdlib.h>
#include <dbus/dbus.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>const int RES_SUCCESS = -1;
const int RES_FAILED = 0;
using namespace std;
//sprintf (answer, "Sum is %d", i + j);const char *const SERVER_BUS = "test.signal.server";
const char *const INTERFACE1 = "test.signal.Type";
const char *const INTERFACE2 = "test.signal.Type2";
const char *const OBJECTPATH1 = "/test/signal/server";
const char *const METHOD_1 = "FunctionOne";
const char *const METHOD_2 = "FunctionTwo";
const char *const SIGNAL_1 = "Test";
const char *const SIGNAL_MUL = "MulType";
const char *const SIGNAL_STRING = "TestString";
const char *const SIGNAL_ARRAY = "Array";int my_dbus_initialization(char const *_bus_name, DBusConnection **_conn)
{DBusError err;int ret;dbus_error_init(&err);*_conn = dbus_bus_get(DBUS_BUS_SESSION, &err);if (dbus_error_is_set(&err)){cout<<"Connection Error:"<<err.message<<endl;dbus_error_free(&err);return RES_FAILED;}ret = dbus_bus_request_name(*_conn, _bus_name,DBUS_NAME_FLAG_REPLACE_EXISTING, &err);if (dbus_error_is_set(&err)){cout<<"Replace error"<<err.message<<endl;dbus_error_free(&err);return RES_FAILED;}if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret){cout<<"dbus is not primary own"<<endl;return RES_FAILED;}return RES_SUCCESS;
}void* wait_signal(void *)
{DBusError err;DBusMessage *msg;DBusMessageIter args;dbus_error_init(&err);DBusConnection *conn;if (RES_FAILED == my_dbus_initialization(SERVER_BUS, &conn)){exit(1);}char match_str[64];memset(match_str, 0, sizeof(match_str));sprintf (match_str, "type='signal',interface='%s'", INTERFACE1);dbus_bus_add_match(conn, match_str,&err); // add rule to matchmemset(match_str, 0, sizeof(match_str));sprintf (match_str, "type='signal',interface='%s'", INTERFACE2);dbus_bus_add_match(conn, match_str, &err); // add rule to matchdbus_connection_flush(conn);if (dbus_error_is_set(&err)){cout<<"dbus_bus_add_match err "<<err.message<<endl;dbus_error_free(&err);return NULL;// RES_FAILED;}cout<<"server start"<<endl;while(1){//cout<<"one circle"<<endl;//dbus_connection_read_write(conn, 0);if (!dbus_connection_read_write(conn, 0)){break;}usleep(1);msg = dbus_connection_pop_message(conn); // receive messageif (NULL == msg){usleep(1);//sleep(1);continue;}if (dbus_message_is_signal(msg, INTERFACE1, SIGNAL_1)){if (!dbus_message_iter_init(msg, &args)){cout<<"dbus_message_iter_init error, msg has no arguments!"<<endl;continue;}if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)){//cout<<"not a uint 32 type!"<<endl;dbus_uint32_t my_age = 0;dbus_message_iter_get_basic(&args, &my_age);cout<<"Got signal with value "<<my_age<<endl;}else {cout<<SIGNAL_1<<" unhandle type"<<endl;}}else if (dbus_message_is_signal(msg, INTERFACE1, SIGNAL_ARRAY)){cout<<SIGNAL_ARRAY<<" is called"<<endl;if (!dbus_message_iter_init(msg, &args)){cout<<"dbus msg iter init failed"<<endl;continue;}DBusMessageIter subIter;dbus_message_iter_recurse(&args, &subIter);int *intArray = NULL;int elementNum = 0;dbus_message_iter_get_fixed_array(&subIter, &intArray, &elementNum);for (int i=0; i<elementNum; ++i){cout<<intArray[i]<<endl;}}else if (dbus_message_is_signal(msg, INTERFACE1, SIGNAL_MUL)){if (!dbus_message_iter_init(msg, &args)){cout<<"dbus_message_iter_init error, msg has no arguments!"<<endl;continue;}do {if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)){dbus_uint32_t my_age = 0;dbus_message_iter_get_basic(&args, &my_age);cout<<"Got signal with value "<<my_age<<endl;}if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)){char* myString = NULL;dbus_message_iter_get_basic(&args, &myString);cout<<"Get signal with string:"<<myString<<endl;}if (DBUS_TYPE_BOOLEAN == dbus_message_iter_get_arg_type(&args)){dbus_bool_t boolFlag = false;dbus_message_iter_get_basic(&args, &boolFlag);cout<<"Get bool value: "<<boolFlag<<endl;}/*if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)){cout<<"get an array"<<endl;int *intArray = NULL;int elementNum = 0;dbus_message_iter_get_fixed_array(&args, &intArray, &elementNum);for (int i=0; i<elementNum; ++i){cout<<intArray[i]<<endl;}}*/}while(dbus_message_iter_next(&args));}else if (dbus_message_is_signal(msg, INTERFACE2, SIGNAL_STRING)){if (!dbus_message_iter_init(msg, &args)){cout<<"dbus_message_iter_init error, msg has no arguments!"<<endl;}else if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)){char* myString = NULL;dbus_message_iter_get_basic(&args, &myString);cout<<"Get signal with string:"<<myString<<endl;}else {cout<<"unhandle type"<<endl;}}else if (dbus_message_is_method_call(msg, INTERFACE1, METHOD_1)){char* param = NULL;if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING,¶m, DBUS_TYPE_INVALID)){cout<<"Method "<<METHOD_1<<" is called and get string: "<<param<<endl;}else{cout<<"error call function"<<endl;}}else if (dbus_message_is_method_call(msg, INTERFACE1, METHOD_2)){char* param = NULL;if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING,¶m, DBUS_TYPE_INVALID)){cout<<"Method "<<METHOD_2<<" is called and get string: "<<param<<endl;}else{cout<<"error call function"<<endl;}}else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")){DBusMessage *reply;const char *introspection_data = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \n""\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n""<node>\n"" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"" <method name=\"Introspect\">\n"" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"" </method>\n"" </interface>\n"" <interface name=\"test.signal.Type\">\n"" <method name=\"FunctionOne\">\n"" <arg direction=\"in\" type=\"s\"/>\n"" </method>\n"" <method name=\"FunctionTwo\">\n"" <arg direction=\"in\" type=\"s\"/>\n"" </method>\n"" </interface>\n""</node>\n";cout<<introspection_data<<endl;reply = dbus_message_new_method_return(msg);dbus_message_append_args(reply, DBUS_TYPE_STRING,&introspection_data,DBUS_TYPE_INVALID);dbus_connection_send(conn, reply, NULL);dbus_message_unref(reply);}dbus_message_unref(msg);}
}int main()
{pthread_t id;int ret;ret = pthread_create(&id, NULL, wait_signal, NULL);if (ret != 0){cout<<"create pthread error"<<endl;}pthread_join(id, NULL);return 0;
}
二,在while循环前注册路径。优点是不需要在循环内部处理消息,结构清晰。将处理消息函数放DBusObjectPathVTable结构中。通过DBusObjectPathVTable中的message_function指向处理函数,在处理函数中判断消息类型并处理。程序结构如下图。
/*
test.signal.server(bus name)|----test.signal.Type(interface1)| || ----Test(signal1)| || ----FunctionOne(method1)| || ----FunctionTwo(method2)----test.signal.Type2(interface2)| || ----TestString(signal2)----org.freedesktop.DBus.Introspectable(interface3)| || ----Introspect(method3)
*/
#include <iostream>
#include <stdlib.h>
#include <dbus/dbus.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>const int RES_SUCCESS = -1;
const int RES_FAILED = 0;
using namespace std;const char *const SERVER_BUS = "test.signal.server";
const char *const INTERFACE1 = "test.signal.Type";
const char *const INTERFACE2 = "test.signal.Type2";
const char *const OBJECTPATH1 = "/test/signal/server";
const char *const METHOD_1 = "FunctionOne";
const char *const METHOD_2 = "FunctionTwo";
const char *const SIGNAL_1 = "Test";
const char *const SIGNAL_2 = "TestString";static DBusHandlerResult method_message(DBusConnection *connection, DBusMessage *request);
static void respond_to_introspect(DBusConnection *connection, DBusMessage *request);
static void respond_to_Method_1(DBusConnection *connection, DBusMessage* request);
static void respond_to_Method_2(DBusConnection *connection, DBusMessage* request);
static void respond_to_Signal_1(DBusConnection *connection, DBusMessage* msg);
static void respond_to_Signal_2(DBusConnection *connection, DBusMessage* msg);int my_dbus_initialization(char const *_bus_name, DBusConnection **_conn)
{DBusError err;int ret;dbus_error_init(&err);*_conn = dbus_bus_get(DBUS_BUS_SESSION, &err);if (dbus_error_is_set(&err)){cout<<"Connection Error:"<<err.message<<endl;dbus_error_free(&err);return RES_FAILED;}ret = dbus_bus_request_name(*_conn, _bus_name,DBUS_NAME_FLAG_REPLACE_EXISTING, &err);if (dbus_error_is_set(&err)){cout<<"Replace error"<<err.message<<endl;dbus_error_free(&err);return RES_FAILED;}if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret){return RES_FAILED;}return RES_SUCCESS;
}static void respond_to_introspect(DBusConnection *connection, DBusMessage *request)
{cout<<"called introspect"<<endl;DBusMessage *reply;const char *introspection_data ="<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \n""\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n""<node>\n"" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"" <method name=\"Introspect\">\n"" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"" </method>\n"" </interface>\n"" <interface name=\"test.signal.Type\">\n"" <method name=\"FunctionOne\">\n"" <arg direction=\"in\" type=\"s\"/>\n"" </method>\n"" <method name=\"FunctionTwo\">\n"" <arg direction=\"in\" type=\"s\"/>\n"" </method>\n"" </interface>\n""</node>\n";reply = dbus_message_new_method_return(request);if (!dbus_message_append_args(reply, DBUS_TYPE_STRING,&introspection_data,DBUS_TYPE_INVALID)){fprintf(stderr, "append args error");return;}if (!dbus_connection_send(connection, reply, NULL)){fprintf(stderr, "Out Of Memory!\n");return;}dbus_message_unref(reply);
}static void respond_to_Method_1(DBusConnection *connection, DBusMessage *request)
{DBusError dbus_error;dbus_error_init(&dbus_error);char* param = NULL;if (dbus_message_get_args(request, &dbus_error, DBUS_TYPE_STRING,¶m, DBUS_TYPE_INVALID)){cout<<"Method "<<METHOD_1<<" is called and get string: "<<param<<endl;}else{cout<<"error call function"<<endl;}
}static void respond_to_Method_2(DBusConnection *connection, DBusMessage *request)
{DBusError dbus_error;dbus_error_init(&dbus_error);char* param = NULL;if (dbus_message_get_args(request, &dbus_error, DBUS_TYPE_STRING,¶m, DBUS_TYPE_INVALID)){cout<<"Method "<<METHOD_2<<" is called and get string: "<<param<<endl;}else{cout<<"error call function"<<endl;}
}static void respond_to_Signal_1(DBusConnection *connection, DBusMessage *msg)
{DBusMessageIter args;if (!dbus_message_iter_init(msg, &args)){cout<<"dbus_message_iter_init error, msg has no arguments!"<<endl;}else if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)){dbus_uint32_t ivalue = 0;dbus_message_iter_get_basic(&args, &ivalue);cout<<"Got signal with value "<<ivalue<<endl;}else {cout<<"unhandle type"<<endl;}
}static void respond_to_Signal_2(DBusConnection *connection, DBusMessage *msg)
{DBusMessageIter args;if (!dbus_message_iter_init(msg, &args)){cout<<"dbus_message_iter_init error, msg has no arguments!"<<endl;}else if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)){char* myString = NULL;dbus_message_iter_get_basic(&args, &myString);cout<<"Get signal with string:"<<myString<<endl;}else {cout<<"unhandle type"<<endl;}
}static DBusHandlerResult method_message(DBusConnection *connection, DBusMessage *message, void *user_data)
{const char *interface_name = dbus_message_get_interface(message);const char *member_name = dbus_message_get_member(message);cout<<interface_name <<" "<< member_name<<endl;if (0 == strcmp("org.freedesktop.DBus.Introspectable", interface_name) &&0 == strcmp("Introspect", member_name)){respond_to_introspect(connection, message);return DBUS_HANDLER_RESULT_HANDLED;}else if (0 == strcmp(INTERFACE1, interface_name) && 0 == strcmp(METHOD_1, member_name)){respond_to_Method_1(connection, message);return DBUS_HANDLER_RESULT_HANDLED;}else if (0 == strcmp(INTERFACE1, interface_name) && 0 == strcmp(METHOD_2, member_name)){respond_to_Method_2(connection, message);return DBUS_HANDLER_RESULT_HANDLED;}else if (0 == strcmp(INTERFACE1, interface_name) && 0 == strcmp(SIGNAL_1, member_name)){cout<<"signal is called"<<endl;respond_to_Signal_1(connection, message);return DBUS_HANDLER_RESULT_HANDLED;}else if (0 == strcmp(INTERFACE2, interface_name) && 0 == strcmp(SIGNAL_2, member_name)){cout<<"signal 2 is called"<<endl;respond_to_Signal_2(connection, message);return DBUS_HANDLER_RESULT_HANDLED;}else{return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}
}void* wait_signal(void *)
{DBusError err;DBusMessage *msg;DBusMessageIter args;dbus_error_init(&err);DBusConnection *conn;if (RES_FAILED == my_dbus_initialization(SERVER_BUS, &conn)){exit(1);}char match_str[64];memset(match_str, 0, sizeof(match_str));sprintf (match_str, "type='signal',interface='%s'", INTERFACE1);dbus_bus_add_match(conn, match_str,&err); // add rule to match//memset(match_str, 0, sizeof(match_str));//sprintf (match_str, "type='signal',interface='%s'", INTERFACE2);//dbus_bus_add_match(conn, match_str, &err); // add rule to matchdbus_connection_flush(conn);if (dbus_error_is_set(&err)){cout<<"dbus_bus_add_match err "<<err.message<<endl;return NULL;// RES_FAILED;}cout<<"server start"<<endl;DBusObjectPathVTable vtable;vtable.message_function = method_message;vtable.unregister_function = NULL;dbus_connection_try_register_object_path(conn,OBJECTPATH1,&vtable,NULL,&err);while(1){if (!dbus_connection_read_write_dispatch(conn, 0)){fprintf(stderr, "Noe connected now.\n");break;}usleep(1);}
}int main()
{pthread_t id;int ret;ret = pthread_create(&id, NULL, wait_signal, NULL);if (ret != 0){cout<<"create pthread error"<<endl;}pthread_join(id, NULL);return 0;
}
三,采用select函数监听设备变化,将select函数放在监听循环中。优点是可以同时监听其他消息,如可以监听TCP和UDP。程序结构如下图。
实例