DBUS服务器端程序

有些话、适合烂在心里 提交于 2019-12-19 19:51:22

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,
                                      &param, 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,
                                      &param, 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,
                        &param, 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,
                        &param, 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。程序结构如下图。

实例

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!