Openwrt ubus: 进程间通信的例子

ubus是Openwrt实现进程间通信的总线机制,由ubusd守护进程、ubus服务端和ubus客户端协作完成通信。守护进程负责消息转发,服务端提供功能模块,客户端发起请求。文中给出具体实现例子,在openwrt widora环境编译通过,还尝试将ubus封装成模块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ubus是Openwrt实现进程间通信的一种总线机制,  由三部分协作完成通信过程:ubusd守护进程,ubus服务端,ubus客户端。

1. ubusd守护进程: 管理ubus服务端和客户端的注册,并作为服务端和客户端的中间人, 进行消息转发, 所有消息均封装成json格式。向ubus服务端传递ubus客户端的请求(call),向ubus客户端传递ubus服务端的执行结果。

2. ubus服务端(ubus server object):  提供软件各种具体功能模块的实现(methods), 服务端的对象名称和具体的mothd名称向ubusd进行注册后,就可以被其他ubus客户端进行传呼(call) 。

3. ubus客户端(ubus client object):  是具体功能(method)的传呼方(caller), 其通用ubusd向某个ubus服务端呼叫请求(call)执行指定method。

4. 实际上,一个ubus object对象,即可以作为服务端提供各种方法(method),也可以作为客户端来传呼(call)其他对象的方法。

5. 下面是具体的实现例子:

ubus_server.c:     向ubusd注册了一个名为"ering_uobj"的对象 ,  提供一个名称为"ering_method“的方法, 这个方法的实现依靠3个名称为"id","data","msg"的参数。 为了简单实现这个例子, 程序只将收到的这3个参数打印出来, 完成后向客户端传送一条确认消息。方法请求是通过回调函数来实现的,程序本身不会退出。

/*------------------------ ubus_server.c -----------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

An example for Openwrt UBUST communication.

Midas Zhou
---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <libubus.h>

static struct ubus_context *ctx;
static struct ubus_request_data req_data;
static struct blob_buf	bb;

static int ering_handler( struct ubus_context *ctx, struct ubus_object *obj,
			  struct ubus_request_data *req, const char *method,
			  struct blob_attr *msg );

/* Enum for EGI policy order */
enum {
	ERING_ID,
	ERING_DATA,
	ERING_MSG,
	__ERING_MAX,
};

/* Ubus Policy */
static const struct blobmsg_policy ering_policy[] =
{
	[ERING_ID]  = { .name="id", .type=BLOBMSG_TYPE_INT32},
	[ERING_DATA] = { .name="data", .type=BLOBMSG_TYPE_INT32 },
	[ERING_MSG] = { .name="msg", .type=BLOBMSG_TYPE_STRING },
};

/* Ubus Methods */
static const struct ubus_method ering_methods[] =
{
	UBUS_METHOD("ering_method", ering_handler, ering_policy),
};

/* Ubus object type */
static struct ubus_object_type ering_obj_type =
	UBUS_OBJECT_TYPE("ering_uobj", ering_methods);

/* Ubus object */
static struct ubus_object ering_obj=
{
	.name = "ering.host", 	/* with APP name */
	.type = &ering_obj_type,
	.methods = ering_methods,
	.n_methods = ARRAY_SIZE(ering_methods),
	//.path= /* useless */
};


void main(void)
{
	int ret;
	const char *ubus_socket=NULL; /* use default UNIX sock path: /var/run/ubus.sock */

	/* 1. create an epoll instatnce descriptor poll_fd */
	uloop_init();

	/* 2. connect to ubusd and get ctx */
	ctx=ubus_connect(ubus_socket);
	if(ctx==NULL) {
		printf("Fail to connect to ubusd!\n");
		return;
	}

	/* 3. registger epoll events to uloop, start sock listening */
	ubus_add_uloop(ctx);

	/* 4. register a usb_object to ubusd */
	ret=ubus_add_object(ctx, &ering_obj);
	if(ret!=0) {
		printf("Fail to register an object to ubus.\n");
		goto UBUS_FAIL;

	} else {
		printf("Add '%s' to ubus @%u successfully.\n", ering_obj.name, ering_obj.id);
	}

	/* 5. uloop routine: events monitoring and callback provoking */
	uloop_run();


	uloop_done();
UBUS_FAIL:
	ubus_free(ctx);
}


/*---------------------------------------------
A callback function for ubus methods handling
----------------------------------------------*/
static int ering_handler( struct ubus_context *ctx, struct ubus_object *obj,
			  struct ubus_request_data *req, const char *method,
			  struct blob_attr *msg )
{
	struct blob_attr *tb[__ERING_MAX]; /* for parsed attr */

	/* Parse blob_msg from the caller to request policy */
	blobmsg_parse(ering_policy, ARRAY_SIZE(ering_policy), tb, blob_data(msg), blob_len(msg));

	/* print request msg */
	printf("Receive msg from caller: ");
	if(tb[ERING_ID])
	     printf("UBUS_ID=%u  ", blobmsg_get_u32(tb[ERING_ID]));
	if(tb[ERING_DATA])
	     printf("DATA=%u  ", blobmsg_get_u32(tb[ERING_DATA]));
	if(tb[ERING_MSG])
	     printf("MSG='%s' \n", blobmsg_data(tb[ERING_MSG]));

	/* Do some job here according to caller's request */

	/* send a reply msg to the caller for information */
	blob_buf_init(&bb, 0);
	blobmsg_add_string(&bb,"Ering reply", "Request is being proceeded!");
	ubus_send_reply(ctx, req, bb.head);

	/* 	-----  reply results to the caller -----
	 * NOTE: we may put proceeding job in a timeout task, just to speed up service response.
	 */
	ubus_defer_request(ctx, req, &req_data);
	ubus_complete_deferred_request(ctx, req, UBUS_STATUS_OK);
}

ubus_client.c:       向ubusd注册了一个名为"ering_caller" 的对象, 没有注册任何method。它向"ering_uobj"对象传呼(call)了"ering_method"方法,  在接收到服务端反馈的消息后将它打印出来,然后退出程序。

/*-------------------------  ubus_client.c  ------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

An example for Openwrt UBUS communication.

Midas Zhou
------------------------------------------------------------------*/
#include <stdio.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>

static struct ubus_context *ctx;
static struct blob_buf	bb;

static void result_handler(struct ubus_request *req, int type, struct blob_attr *msg);

/* ubus object assignment */
static struct ubus_object ering_obj=
{
	.name = "ering_caller",
	#if 0
	.type = &ering_obj_type,
	.methods = ering_methods,
	.n_methods = ARRAY_SIZE(ering_methods),
	.path= /* useless */
	#endif
};


void main(void)
{
	int ret;
	uint32_t host_id; /* ering host id */
	const char *ubus_socket=NULL; /* use default UNIX sock path: /var/run/ubus.sock */

	/* 1. create an epoll instatnce descriptor poll_fd */
	uloop_init();

	/* 2. connect to ubusd and get ctx */
	ctx=ubus_connect(ubus_socket);
	if(ctx==NULL) {
		printf("Fail to connect to ubusd!\n");
		return;
	}

	/* 3. registger epoll events to uloop, start sock listening */
	ubus_add_uloop(ctx);

	/* 4. register a usb_object to ubusd */
	ret=ubus_add_object(ctx, &ering_obj);
	if(ret!=0) {
		printf("Fail to register an object to ubus.\n");
		goto UBUS_FAIL;

	} else {
		printf("Add '%s' to ubus @%u successfully.\n",ering_obj.name, ering_obj.id);
	}

	/* 5. search a registered object with a given name */
	if( ubus_lookup_id(ctx, "ering.host", &host_id) ) {
		printf("ering.host is NOT found in ubus!\n");
		goto UBUS_FAIL;
	}
	printf("ering.host is found in ubus @%u.\n",host_id);

	/* 6. prepare request method policy and data */
	blob_buf_init(&bb,0);
	blobmsg_add_u32(&bb,"id", ering_obj.id); 	/* ERING_ID */
	blobmsg_add_u32(&bb,"data", 123456); 		/* ERING_DATA */
	blobmsg_add_string(&bb,"msg", "Hello, ERING!"); /* ERING_DATA */

	/* 7. call the ubus host object */
	ret=ubus_invoke(ctx, host_id, "ering_method", bb.head, result_handler, 0, 3000);
	printf("Call result: %s\n", ubus_strerror(ret));

	/* 8. uloop routine: events monitoring and callback provoking
	      However, we just ignore uloop in this example.
	 */
	 //uloop_run();

	uloop_done();
UBUS_FAIL:
	ubus_free(ctx);
}

/* callback function for ubus_invoke to process result from the host
 * Here we just print out the message.
 */
static void result_handler(struct ubus_request *req, int type, struct blob_attr *msg)
{
        char *strmsg;

        if(!msg)
                return;

        strmsg=blobmsg_format_json_indent(msg,true, 0); /* 0 type of format */
        printf("Response from the host: %s\n", strmsg);
        free(strmsg); /* need to free strmsg */
}

6.  本例子在openwrt  widora环境下编译通过, Makefile 如下, Makefile环境变量请根据自己实际情况修改:

export STAGING_DIR=/home/midas-zhou/openwrt_widora/staging_dir
COMMON_USRDIR=/home/midas-zhou/openwrt_widora/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/
CC= $(STAGING_DIR)/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mipsel-openwrt-linux-gcc

CFLAGS  += -I$(COMMON_USRDIR)/include
LDFLAGS += -L$(COMMON_USRDIR)/lib
LIBS   += -lubus -lubox -lblobmsg_json -ljson_script -ljson-c

all:	 ubus_server ubus_client

ubus_server:   ubus_server.c
	$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) ubus_server.c -o ubus_server 

ubus_client:   ubus_client.c
	$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) ubus_client.c -o ubus_client

clean:
	rm -rf *.o ubus_server ubus_client

7.  试着将ubus封装成EGI RING模块, 以方便程序调用。具体代码见  https://github.com/widora/ctest/tree/master/wegi/ering

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Midas-Zhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值