dbus 简单编程(二)

---->dbus spec:https://dbus.freedesktop.org/doc/dbus-specification.html

---->dbus通信原理如图下:

dbus 简单编程(二)_第1张图片

---->以下实现为总线上的对象访问方式:请求发送.接下来做一个代理的例子

一. 这一部分称为client端,简单的说,就是请求服务端,源码如下:

client.c

#include 
#include 
#include 
#include 
#include 


DBusConnection* init_bus()
{
	DBusConnection *connection;
	DBusError err;
	int ret;

	dbus_error_init(&err);
        //连接到dbus,建立一个连接,称为对象
	connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
	if(dbus_error_is_set(&err))
	{
		printf("connection error: :%s -- %s\n", err.name, err.message);
		dbus_error_free(&err);
		return NULL;
	}
        //为这个对象分配一个名字
	ret = dbus_bus_request_name(connection, "hello.world.client", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
	if(dbus_error_is_set(&err))
	{
		printf("Name error: %s -- %s\n", err.name, err.message);
		dbus_error_free(&err);
		return NULL;
	}
	if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
		return NULL;

	return connection;
}


void send_signal(DBusConnection *connection)
{
	DBusMessage *msg;
	DBusMessageIter arg;
	char *str = "hello world!";


	//创建一个signal对象
	//param1: path (这个逻辑来说,可以是任何字符串,只要符合规则即可)
	//param2: interface (一样)
	//param3: 信号方法名(必须与服务端名匹配)
	if((msg = dbus_message_new_signal("/hello", "aa.bb.cc", "alarm_test")) == NULL)
	{
		printf("message is NULL\n");
		return;
	}
#if 0
	 //这个看需求添加,一般来说,信号是一种单向广播,加上这一句变单向单播
	 //param2: bus_name
	if(!dbus_message_set_destination(msg, "hello.world.service"))
        {
                printf("memory error\n");
        }
#endif

	//添加参数的一些接口
	dbus_message_iter_init_append(msg, &arg);
	dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &str);
	//入队
	dbus_connection_send(connection, msg, NULL);
	//发送
	dbus_connection_flush(connection);
	//释放内存
	dbus_message_unref(msg);

	return;
}

void send_method_call(DBusConnection *connection)
{
	DBusMessage *msg;
	DBusMessageIter arg;
	DBusPendingCall *pending;
	int a = 100;
	int b = 99;
	int sum;

	msg = dbus_message_new_method_call("hello.world.service", "/hello/world","hello.world", "add");
	if(msg == NULL)
	{
		printf("no memory\n");
		return;
	}

	dbus_message_iter_init_append(msg, &arg);
    	if(!dbus_message_iter_append_basic (&arg, DBUS_TYPE_INT32,&a)){
        	printf("no memory!");
        	dbus_message_unref(msg);
        	return;
    	}
   	if(!dbus_message_iter_append_basic (&arg, DBUS_TYPE_INT32,&b)){
        	printf("no memory!");
        	dbus_message_unref(msg);
        	return;
    	}

    //入队message,等待回复
    //param1: 连接描述符
    //param2: message
    //param3: 相当于一个回调的一个描述符,为了获了返回的消息
    //param4: 超时间. -1代表无限
    if(!dbus_connection_send_with_reply (connection, msg, &pending, -1)){
        printf("no memeory!");
        dbus_message_unref(msg);
        return;
    }

    if(pending == NULL){
        printf("Pending is NULL, may be disconnect...\n");
        dbus_message_unref(msg);
        return;
    }
    //send
    dbus_connection_flush(connection);
    dbus_message_unref(msg);
	
	//阻塞,直到接收到一个响应.
    dbus_pending_call_block (pending);
    msg = dbus_pending_call_steal_reply (pending);
    if (msg == NULL) {
    	printf("reply is null. error\n");
    	return;
    }
    //释放pending内存 
    dbus_pending_call_unref(pending);
    //解析参数
    if (!dbus_message_iter_init(msg, &arg))
        printf("no argument, error\n");
    if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_INT32)
    {
    	printf("paramter type error\n");
    }

    dbus_message_iter_get_basic(&arg, &sum);

    printf(" a(%d) + b(%d) = %d\n",a, b, sum);
    dbus_message_unref(msg);
	
    return;
}


int main(int argc, char **argv)
{
	DBusConnection *connection;

	connection = init_bus();
	if(connection == NULL)
	{
		printf("connect to bus failed...\n");
		return -1;
	}
        //发送一个信号及一个方法调用
	send_signal(connection);
	send_method_call(connection);
	
	return 0;
}

二.服务端,就是为其他对象提供服务, 源码如下:

service.c

#include 
#include 
#include 
#include 
#include 

DBusConnection* init_bus()
{
	DBusConnection *connection;
	DBusError err;
	int ret = 0;

	dbus_error_init(&err);

	//与session dbus 建立连接
	//param1:bus type = {DBUS_BUS_SESSION, DBUS_BUS_SYSTEM} 一个系统dbus, 一个普通用户dbus
	//param2:错误信息,包括错误名与错误信息.
	connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
	if(dbus_error_is_set(&err))
	{
		printf("Connection Error: %s--%s\n", err.name, err.message);
		dbus_error_free(&err);
		return NULL;
	}

	//为连接设置一个bus name: bus_name;
	//param 1: 连接描述符
	//param 2: 请求bus要分配的bus name(逻辑上讲,bus name可以是任何字符串,只要符合命名规则)
	//param 3: flags ={DBUS_NAME_FLAG_REPLACE_EXISTING, 
	//					DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
	//					DBUS_NAME_FLAG_DO_NOT_QUEUE
	//					 }
	//param 4: err info
	ret = dbus_bus_request_name(connection, "hello.world.service", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
	if(dbus_error_is_set(&err))
	{ printf("Name Error: %s--%s\n", err.name, err.message);
		dbus_error_free(&err);
		return NULL;
	}

	if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
		return NULL;

	//注册感兴趣的signal: 来自接口dbus.test.signal.sender
	//param1: 连接描述符
	//param2: match rule (常用的类型: sender=
	//									interface=
	//									type=
	//									member= )
	//param3: err info
	//只设置一个type = signal,表示所有信号都接受.也可以加上接口,发送者bus_name
	dbus_bus_add_match(connection, "type='signal'", &err);
	//阻塞,直到消息发送成功.
	dbus_connection_flush(connection);
	if(dbus_error_is_set(&err))
	{
		printf("add Match Error %s--%s\n", err.name, err.message);
		dbus_error_free(&err);
		return connection;
	}
	return connection;
}

void handle_message(DBusConnection *connection)
{
	DBusMessage *msg;
	DBusMessageIter arg;
	char *str;

	while(1)
	{
		//param1: 连接描述符
		//param2: 超时时间, -1无限超时时间
		dbus_connection_read_write(connection, 0);
		//从队列中取出一条消息
		msg = dbus_connection_pop_message(connection); 
		if(msg == NULL)
		{
			sleep(1);
			continue;
		}
		//这里应该过滤path,暂且不做
		//打印出消息对象路径
		printf("path: %s\n", dbus_message_get_path (msg));
		//param1: message
		//param2: interface 这个名字必须与发送那个接口一样.才能处理
		//param3: singal name 方法名也必须一样.
		if(dbus_message_is_signal(msg, "aa.bb.cc", "alarm_test"))
		{
			//解析message 参数,0为无参数.
			if(!dbus_message_iter_init(msg, &arg))
			{
				printf("no argument\n");
			}
			//获取第一个参数类型
			if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_INVALID)
			{
				//获取参数的值
				dbus_message_iter_get_basic(&arg,&str);
				printf("recv param --: %s\n", str);
			}
			
		}
		else if(dbus_message_is_method_call(msg, "hello.world", "add"))
		{/////处理 add 远程调用.
			DBusMessage *rp;
			DBusMessageIter r_arg;
			int a = 0;
			int b = 0;
			int sum = 0;
			printf("service: add  function\n");

			if(!dbus_message_iter_init(msg, &arg))
			{
				printf("no argument!\n");
				goto out;
			}
			if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_INT32)
			{
				printf("argument error\n");
				goto out;
			}
			dbus_message_iter_get_basic(&arg, &a);

			if(!dbus_message_iter_next(&arg))
			{
				printf("too few argument!\n");
				goto out;
			}
			//check argument type....
			dbus_message_iter_get_basic(&arg, &b);
			sum = a + b;
out:
			//new 一个回应对象
			rp = dbus_message_new_method_return(msg);
			dbus_message_iter_init_append(rp, &r_arg);
			if(!dbus_message_iter_append_basic(&r_arg, DBUS_TYPE_INT32, &sum))
			{
				printf("no memory!!\n");
				return; 
			}

			//param3: 这个跟消息序列有关
			if(!dbus_connection_send(connection, rp, NULL))
			{
				printf("no memory!!\n");
				return;
			}
			dbus_connection_flush(connection);
			dbus_message_unref(rp);
		}
		//释放空间
		dbus_message_unref(msg);
	}
	//dbus_bus_remove_match();
	
}

int main(int argc, char **argv)
{
	int ret = 0;
	DBusConnection *connection;

	connection = init_bus();
	if(connection == NULL)
	{
		printf("connect the dbus failed...\n");
		return -1;
	}

	handle_message(connection);

	return 0;
}

--仔细看一下发送及调用流程.先做到简单的会用.

需安装libdbus-1-dev libdbus-glib-1-dev

编译: gcc client.c -ldbus-1 -I/usr/include/dbus-1 -o client

            gcc service.c -ldbus-1 -I/usr/include/dbus-1 -o service

            有可能会提示找不dbus-arch-deps.h头文件,在系统中搜一下,然后拷贝到/usr/include/dbus-1.0/dbus目录

运行:

1. 先运行: dbus-launch  这个如果有问题,加一参数运行: dbus-launch --sh-syntax

june@june:~/document/method$ dbus-launch 
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-ZkvUxSYjDt,guid=2725ec7c229349533242c8a45b34ac2e
DBUS_SESSION_BUS_PID=2934
DBUS_SESSION_BUS_WINDOWID=71303169

 

2.导出这个变量 

 

export DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-ZkvUxSYjDt,guid=2725ec7c229349533242c8a45b34ac2e

3. 运行 ./service &

4. 运行 ./client &

观察结果,分析.

你可能感兴趣的:(linux常用,DBus)