ubus 工作原理#
在使用 ubus 进行进程间通信时,通常不需要通过共享对象(.so
文件)来直接调用另一个守护进程的函数。ubus 提供了一种更高层次的抽象,使得进程可以通过消息传递的方式调用其他进程提供的服务或方法。
在 ubus 框架中,当一个守护进程注册了一个服务方法后,该方法的代码会被编译进守护进程的可执行文件中,并在守护进程启动时加载到内存中。然而,这个方法的实际执行是在被其他进程通过 ubus 调用时才发生的。具体来说,有以下几个关键点:
守护进程启动:
当守护进程启动时,它会初始化 ubus 上下文,并注册一个或多个服务对象。
注册的服务对象包含方法及其对应的处理函数。
这些方法的代码和数据结构会被加载到内存中,但方法本身不会立即执行。
方法注册:
守护进程通过调用
ubus_add_object
将服务对象注册到 ubus 服务器。这个过程中,ubus 服务器会记录服务对象及其方法的信息,但不会执行这些方法。
方法调用:
当其他进程通过 ubus 调用注册的方法时,ubus 服务器会将调用请求转发给相应的守护进程。
守护进程接收到请求后,会调用对应的方法处理函数来处理请求。
方法处理函数在被调用时才会实际执行,处理请求并返回结果。
示例说明#
假设有一个守护进程 mydaemon
,它注册了一个名为 exampleMethod
的方法:
#include <libubus.h>
#include <blobmsg_json.h>
struct ubus_context* ctx;
struct ubus_object obj;
struct ubus_method methods[] = {
UBUS_METHOD("exampleMethod", example_method_handler, example_method_policy),
};
static const struct ubus_object_type obj_type = UBUS_OBJECT_TYPE("exampleService", methods);
static struct ubus_object obj = {
.name = "exampleService",
.type = &obj_type,
.methods = methods,
.n_methods = ARRAY_SIZE(methods),
};
// 方法处理函数
static int example_method_handler(struct ubus_context* ctx, struct ubus_object* obj,
struct ubus_request_data* req, const char* method,
struct blob_attr* msg) {
// 处理请求
printf("exampleMethod called\n");
return 0;
}
int main() {
// 初始化 ubus 上下文
ctx = ubus_connect(NULL);
if (!ctx) {
fprintf(stderr, "Failed to connect to ubus\n");
return -1;
}
// 注册对象
ubus_add_object(ctx, &obj);
// 进入事件循环
ubus_loop(ctx, NULL, 0);
return 0;
}
在这个示例中:
exampleMethod
的处理函数example_method_handler
会被编译进mydaemon
的可执行文件中,并在守护进程启动时加载到内存中。但是,
example_method_handler
函数只有在其他进程通过 ubus 调用exampleMethod
时才会被执行。
常用指令#
查看已注册的 ubus objects#
ubus list
查看 object 包含的 functions#
ubus -v list system
调用 object 的 method#
# 无参调用
ubus call system info
# 带参数调用
ubus call system signal '{"pid": 5089, "signum": 9}'
监听和广播事件#
ubus listen &
ubus send foo '{ "bar": "baz" }'
help#
Usage: ubus [<options>] <command> [arguments...]
Options:
-s <socket>: Set the unix domain socket to connect to
-t <timeout>: Set the timeout (in seconds) for a command to complete
-S: Use simplified output (for scripts)
-v: More verbose output
-m <type>: (for monitor): include a specific message type
(can be used more than once)
-M <r|t> (for monitor): only capture received or transmitted traffic
Commands:
- list [<path>] List objects
- call <path> <method> [<message>] Call an object method
- subscribe <path> [<path>...] Subscribe to object(s) notifications
- listen [<path>...] Listen for events
- send <type> [<message>] Send an event
- wait_for <object> [<object>...] Wait for multiple objects to appear on ubus
- monitor Monitor ubus traffic
总结#
加载到内存:方法的代码和数据结构在守护进程启动时会被加载到内存中。
实际执行:方法的处理函数只有在被其他进程通过 ubus 调用时才会实际执行。
这种设计使得 ubus 能够高效地管理进程间通信,同时保持良好的性能和资源利用。