ubus客户端向服务器请求信息的例子

本文介绍OpenWRT环境下Ubus通信机制,通过一个客户端请求AP信息的实例,展示了服务器端如何处理请求并返回数据,同时给出了客户端代码实现。

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

openwrt用户空间进中通信常用的通信方式是使用ubus通信,下面给出一个例子,是客户端向服务器请求ap的个数。

 

服务器端代码

 

#include <unistd.h>
#include <signal.h>

#include "libubus.h"

static struct ubus_context *ctx;
static struct blob_buf b;

enum {
	REQ_STATION_COUNT,
	REQ_AP_NAME,
	__REQ_MAX
};

/* 接收的解析格式, client发送过来的调用是 blobmsg_add_u32(&b, "getcnt", ap_index); */
static const struct blobmsg_policy fun2_message_parse_policy[__REQ_MAX] = {
	[REQ_STATION_COUNT] = { .name = "getcnt", .type = BLOBMSG_TYPE_INT32 },
	[REQ_STATION_COUNT] = { .name = "apname", .type = BLOBMSG_TYPE_STRING },
};

static int fun2_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[__REQ_MAX];
	//模拟ap数组中station的个数
	int ap_array[] = {-1, 11111,22222,33333};
	int ap_index;

	blobmsg_parse(fun2_message_parse_policy, __REQ_MAX, tb, blob_data(msg), blob_len(msg));
	if (!tb[REQ_STATION_COUNT])
		return UBUS_STATUS_INVALID_ARGUMENT;
		
	ap_index = blobmsg_get_u32(tb[REQ_STATION_COUNT]);
	
	fprintf(stdout, "someone ask the ap[%d]' info \n", ap_index);
	
	if (ap_index > (sizeof(ap_array) / sizeof(int)))
		ap_index = 0;
		
	
	blob_buf_init(&b, 0);
	//返回客户端请求的station个数
	blobmsg_add_u32(&b, "stacnt", ap_array[ap_index]);
	//发送
	ubus_send_reply(ctx, req, b.head);
	
	return 0;
}


static const struct ubus_method test_methods[] = {
	UBUS_METHOD("fun2", fun2_handler, fun2_message_parse_policy),
};

static struct ubus_object_type test_object_type =
	UBUS_OBJECT_TYPE("server_fun", test_methods);

	//定义一个ubus 对象。
	//其他进程通过调用相应字符串给执行对应的回调函数
	//注册成功后可以通过命令ubus list -v 查看到obj
	//' server_fun' @79a8beac
	// 		"fun2" : {"getcnt":"Iterger","apname":"String"}
static struct ubus_object test_object = {
	.name = "server_fun",
	.type = &test_object_type,
	.methods = test_methods,
	.n_methods = ARRAY_SIZE(test_methods),
};

static void server_main(void)
{
	int ret;

	//向ubusd新增一个对象,之后test_object在ubusd中有一个id号,其他进程通过该id号来向test_object发送消息。
	ret = ubus_add_object(ctx, &test_object);
	if (ret)
		fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));

	uloop_run();
}

int main(int argc, char **argv)
{
	const char *ubus_socket = NULL;
	int ch;

	while ((ch = getopt(argc, argv, "cs:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		default:
			break;
		}
	}

	argc -= optind;
	argv += optind;

	uloop_init();
	signal(SIGPIPE, SIG_IGN);

	ctx = ubus_connect(ubus_socket);
	if (!ctx) {
		fprintf(stderr, "Failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(ctx);

	server_main();

	ubus_free(ctx);
	uloop_done();

	return 0;
}

 


客户端代码

 

#include <sys/time.h>
#include <unistd.h>

#include "libubus.h"

static struct ubus_context *ctx;
static struct blob_buf b;

enum {
	RETURN_CODE,
	__RETURN_MAX,
};

static const struct blobmsg_policy return_policy[__RETURN_MAX] = {
	[RETURN_CODE] = { .name = "stacnt", .type = BLOBMSG_TYPE_INT32 },
};

static void get_result_data_cb(struct ubus_request *req,
				    int type, struct blob_attr *msg)
{
	struct blob_attr *tb[__RETURN_MAX];
	int rc;
	
	//返回的数据也是有tlv格式的,按照return_policy格式进行解析。
	blobmsg_parse(return_policy, __RETURN_MAX, tb, blob_data(msg), blob_len(msg));
	if (!tb[RETURN_CODE]) {
		fprintf(stderr, "No return code received from server\n");
		return;
	}

	rc = blobmsg_get_u32(tb[RETURN_CODE]);

	fprintf(stderr, "get station number is %d \n", rc);
}

static void client_main(void)
{
	static struct ubus_request req;
	uint32_t id;
	int ret;
	int ap_index=2;

	//查找ubusd上的server_fun对象。该对象由server端注册
	if (ubus_lookup_id(ctx, "server_fun", &id)) {
		fprintf(stderr, "Failed to look up test object\n");
		return;
	}

	//b 为全局变量,初始化
	blob_buf_init(&b, 0);
	
	//添加发送buffer的tlv,格式由server_main.c的fun2_message_parse_policy定义
	blobmsg_add_u32(&b, "getcnt", ap_index);
	
	//触发server端注册的函数,并接收返回值,处理函数为get_result_data_cb
	ubus_invoke(ctx, id, "fun2", b.head, get_result_data_cb, NULL, 3000);
}

int main(int argc, char **argv)
{
	const char *ubus_socket = NULL;
	int ch;

	while ((ch = getopt(argc, argv, "cs:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		default:
			break;
		}
	}

	argc -= optind;
	argv += optind;

	uloop_init();

	ctx = ubus_connect(ubus_socket);
	if (!ctx) {
		fprintf(stderr, "Failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(ctx);

	client_main();

	ubus_free(ctx);
	uloop_done();

	return 0;
}


以上代码:服务器端向ubusd注册了个server_fun的服务器对象,客户端通过server_fun ubus对象与服务器端通信。

 

其他:ubus shell调用格式

ubus send linkinspect '{"ac_cmd":1}'

### ubus 服务器配置与使用指南 ubus 是 OpenWrt 系统中的核心通信机制,作为统一总线(Unified Bus),它实现了系统内部各模块之间的高效通信。在 OpenWrt 中,ubus 不仅承担了进程间通信(IPC)的职责,还为开发者提供了灵活的接口用于构建自定义服务。 #### 配置与管理 ubus 的运行依赖于守护进程 `ubusd`,该进程负责注册对象、路由调用,并提供远程过程调用(RPC)功能。通常情况下,ubus 会随着系统的启动自动运行,无需额外配置。如果需要手动启动或重启 ubus 服务,可以使用以下命令: ```bash /etc/init.d/ubus restart ``` OpenWrt 使用 UCI(Unified Configuration Interface)进行配置管理,ubus 的相关配置文件通常位于 `/etc/config/` 目录下,虽然 ubus 本身并不直接提供大量可配置参数,但其集成的服务可能通过 UCI 接口进行控制 [^1]。 #### 使用方式 ubus 提供了多种方式供用户和开发者与其交互。最常见的是通过命令行工具 `ubus` 进行接口查询和方法调用。例如,查看当前注册的所有 ubus 对象: ```bash ubus list ``` 要调用某个对象的方法并传递参数,可以使用如下格式: ```bash ubus call system board '{}' ``` 此命令将调用 `system` 对象下的 `board` 方法,返回系统硬件信息。更多关于 ubus 命令的使用方式可以通过 `ubus --help` 查看帮助文档获取 [^1]。 #### 开发自定义服务 对于希望基于 ubus 构建自定义服务的开发者来说,首先需要了解如何利用 `libubus` 库实现服务端逻辑。一个基本的服务开发流程包括: 1. 包含必要的头文件 `<libubus.h>`。 2. 定义服务对象及其方法。 3. 注册服务到 ubus 总线。 4. 实现事件监听与响应处理。 下面是一个简单的示例代码片段,展示了如何创建一个 ubus 服务: ```c #include <libubus.h> static int my_method(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { // 处理请求逻辑 return 0; } static const struct ubus_method my_methods[] = { UBUS_METHOD("my_method", my_method, NULL), }; static struct ubus_object_type my_object_type = UBUS_OBJECT_TYPE("my_object", my_methods); static struct ubus_object my_object = UBUS_OBJECT("my_object", &my_object_type); int main(int argc, char **argv) { struct ubus_context *ctx; ctx = ubus_connect(NULL); if (!ctx) { return -1; } ubus_add_object(ctx, &my_object); while (1) { sleep(1); } ubus_free(ctx); return 0; } ``` 编译上述程序时,需链接 `libubus` 库。假设你已经设置了 OpenWrt SDK 环境,可以使用如下命令进行编译: ```bash mipsel-openwrt-linux-gcc -o my_service my_service.c -lubus -lobus ``` 部署完成后,确保服务能够正确注册至 ubus 并响应外部请求 [^1]。 #### 应用场景 ubus 被广泛应用于路由器管理系统中,例如获取系统状态、控制网络接口、配置无线设置等。它简化了模块间的通信流程,提高了系统的可扩展性和稳定性。此外,由于 ubus 支持异步通信模型,因此非常适合用来构建实时性强、响应速度快的应用程序 [^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值