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 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 match
dbus_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 message
if (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 match
dbus_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。程序结构如下图。
来源:CSDN
作者:gdizcm
链接:https://blog.csdn.net/gdizcm/article/details/103617382