[openwrt]ubus实现进程间通信举例介绍了ubus的组件和实现原理,本⽂通过代码实例介绍使⽤ubus进⾏进程间通信的三种⽅式。
1. invoke的⽅式实现端对端通信
最简单的情景就是⼀个提供服务的server端,⼀个请求服务的client端,client请求server的服务。
下⾯的例⼦中,server注册了⼀个名为“scan_prog”的对象,该对象中提供⼀个“scan”⽅法:
ubus_invoke.h:
#ifndef __UBUS_INVOKE_H__
#define __UBUS_INVOKE_H__
#include <json/json.h>
#include <libubox/blobmsg_json.h>
struct prog_attr {
char name[64];
int chn_id;
};
#define PROG_MAX 8
#endif /* __UBUS_INVOKE_H__ */
invoke_server.c:
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <json/json.h>
#include <libubox/blobmsg_json.h>
#include "ubus_invoke.h"
static struct ubus_context * ctx = NULL;
static struct blob_buf b;
static const char * sock_path;
static struct prog_attr uri_list[PROG_MAX] =
{
{"program_beijing", 1},
{"program_guangzhou", 2},
{"program_shanghai", 3},
{"", -1},
};
enum
{
SCAN_CHNID,
SCAN_POLICY_MAX,
};
static const struct blobmsg_policy scan_policy[SCAN_POLICY_MAX] = {
[SCAN_CHNID] = {.name = "chnID", .type = BLOBMSG_TYPE_INT32},
};
static int ubus_start_scan(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int ret = -1;
void * json_list = NULL;
void * json_list = NULL;
void * json_uri = NULL;
int idx;
blob_buf_init(&b, 0);
struct blob_attr *tb[SCAN_POLICY_MAX];
blobmsg_parse(scan_policy, SCAN_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
/*
本例⼦中,如果请求特定的节⽬号,返回节⽬名称。
如果请求节⽬号是0,则返回所有节⽬列表。
*/
if (tb[SCAN_CHNID] != NULL)
{
int chnid = blobmsg_get_u32(tb[SCAN_CHNID]);
进程通信方式if (chnid == 0)
{
json_uri = blobmsg_open_array(&b, "prog_list");
for (idx = 0; idx < PROG_MAX; idx++)
{
if ('\0' != uri_list[idx].name[0])
{
json_list = blobmsg_open_table(&b, NULL);
blobmsg_add_string(&b, "name", uri_list[idx].name);
blobmsg_add_u32(&b, "channel", uri_list[idx].chn_id);
blobmsg_close_table(&b, json_list);
}
}
blobmsg_close_array(&b, json_uri);
ret = 0;
}
else
{
for (idx = 0; idx < PROG_MAX; idx++)
{
if ('\0' != uri_list[idx].name[0] && uri_list[idx].chn_id == chnid)
{
blobmsg_add_string(&b, "name", uri_list[idx].name);
ret = 0;
}
}
}
}
blobmsg_add_u32(&b, "result", ret);
ubus_send_reply(ctx, req, b.head);
return 0;
}
/* ⽅法列表 */
static struct ubus_method scan_methods[] =
{
UBUS_METHOD("scan", ubus_start_scan, scan_policy),
};
/* type⽬前没有实际⽤处 */
static struct ubus_object_type scan_obj_type
= UBUS_OBJECT_TYPE("scan_prog", scan_methods);
static struct ubus_object scan_obj =
{
.name = "scan_prog", /* 对象的名字 */
.type = &scan_obj_type,
.type = &scan_obj_type,
.methods = scan_methods,
.n_methods = ARRAY_SIZE(scan_methods),
};
static void ubus_add_fd(void)
{
ubus_add_uloop(ctx);
#ifdef FD_CLOEXEC
fcntl(ctx->sock.fd, F_SETFD,
fcntl(ctx->sock.fd, F_GETFD) | FD_CLOEXEC);
#endif
}
static void ubus_reconn_timer(struct uloop_timeout *timeout) {
static struct uloop_timeout retry =
{
.cb = ubus_reconn_timer,
};
int t = 2;
if (ubus_reconnect(ctx, sock_path) != 0) {
uloop_timeout_set(&retry, t * 1000);
return;
}
ubus_add_fd();
}
static void ubus_connection_lost(struct ubus_context *ctx) {
ubus_reconn_timer(NULL);
}
static int display_ubus_init(const char *path)
{
uloop_init();
sock_path = path;
ctx = ubus_connect(path);
if (!ctx)
{
printf("ubus connect failed\n");
return -1;
}
printf("connected as %08x\n", ctx->local_id);
ctx->connection_lost = ubus_connection_lost;
ubus_add_fd();
/* 向ubusd注册对象和⽅法,供其他ubus客户端调⽤。 */
if (ubus_add_object(ctx, &scan_obj) != 0)
{
printf("ubus add obj failed\n");
return -1;
}
return 0;
}
static void display_ubus_done(void)
{
if (ctx)
ubus_free(ctx);
}
int main(int argc, char * argv[])
{
char * path = NULL;
if (-1 == display_ubus_init(path))
{
printf("ubus connect failed!\n");
return -1;
}
uloop_run();
display_ubus_done();
return 0;
}
客户端代码invoke_client.c去调⽤server端的"scan_prog"对象的"scan"⽅法:
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <json/json.h>
#include <libubox/blobmsg_json.h>
#include "ubus_invoke.h"
static struct ubus_context * ctx = NULL;
static struct blob_buf b;
static const char * cli_path;
enum
{
SCAN_CHNID,
SCAN_POLICY_MAX,
};
static const struct blobmsg_policy scan_policy[SCAN_POLICY_MAX] = {
[SCAN_CHNID] = {.name = "chnID", .type = BLOBMSG_TYPE_INT32},
};
static int timeout = 30;
static bool simple_output = false;
static void scanreq_prog_cb(struct ubus_request *req, int type, struct blob_attr *msg) {
char *str;
if (!msg)
return;
/*
在这⾥处理返回的消息。
本例⼦只是将返回的消息打印出来。
*/
str = blobmsg_format_json_indent(msg, true, simple_output ? -1 : 0);
printf("%s\n", str);
free(str);
}
static int client_ubus_call()
{
unsigned int id;
unsigned int id;
int ret;
blob_buf_init(&b, 0);
/* 需要传递的参数 */
blobmsg_add_u32(&b, scan_policy[SCAN_CHNID].name, 0);
/*
向ubusd查询是否存在"scan_prog"这个对象,
如果存在,返回其id
*/
ret = ubus_lookup_id(ctx, "scan_prog", &id);
if (ret != UBUS_STATUS_OK) {
printf("lookup scan_prog failed\n");
return ret;
}
else {
printf("lookup scan_prog successs\n");
}
/* 调⽤"scan_prog"对象的"scan"⽅法 */
return ubus_invoke(ctx, id, "scan", b.head, scanreq_prog_cb, NULL, timeout * 1000);
}
/*
ubus_invoke()的声明如下:
int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
struct blob_attr *msg, ubus_data_handler_t cb, void *priv, int timeout);
其中cb参数是消息回调函数,其函数类型定义为:
typedef void (*ubus_data_handler_t)(struct ubus_request *req,
int type, struct blob_attr *msg);
参数type是请求消息的类型,如UBUS_MSG_INVOKE,UBUS_MSG_DATA等。
参数msg存放从服务端得到的回复消息,struct blob_attr类型,同样⽤blobmsg_parse()来解析。
参数req保存了请求⽅的消息属性,其中req->priv即ubus_invoke()中的priv参数,
⽤这个参数可以零活的传递⼀些额外的数据。
*/
static int client_ubus_init(const char *path)
{
uloop_init();
cli_path = path;
ctx = ubus_connect(path);
if (!ctx)
{
printf("ubus connect failed\n");
return -1;
}
printf("connected as %08x\n", ctx->local_id);
return 0;
}
static void client_ubus_done(void)
{
if (ctx)
ubus_free(ctx);
}
int main(int argc, char * argv[])
{
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论