---->dbus spec:https://dbus.freedesktop.org/doc/dbus-specification.html
---->dbus通信原理如图下:
---->以下实现为总线上的对象访问方式:请求发送.接下来做一个代理的例子
一. 这一部分称为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 &
观察结果,分析.