[openwrt] 使用ubus实现
[openwrt] 使用ubus实现
ubus为openwrt平台开发中的进程间通信提供了一个通用的框架。它让进程间通信的实现变得非常简单,并且ubus具有很强的可移植性,可以很方便的移植到其他linux平台上使用。本文描述了ubus的实现原理和整体框架。
ubus源码可通过git库 git://nbd.name/luci2/ubus.git 获得,其依赖的ubox库的git库:git://nbd.name/luci2/ubox.git。
1. ubus的实现框架
ubus实现的基础是unix socket,即本地socket,它相对于用于网络通信的inet socket更高效,更具可靠性。unix socket客户端和服务器的实现方式和网络socket类似,读者如果还不太熟悉可查阅相关资料。
我们知道实现一个简单的unix socket服务器和客户端需要做如下工作:
- 建立一个socket server端,绑定到一个本地socket文件,并监听clients的连接。
- 建立一个或多个socket client端,连接server。
- client和server相互发送消息。
- client或server收到对方消息后,针对具体消息进行相应处理。
ubus同样实现了上述组件,并对socket连接以及消息传输和处理进行了封装:
- 1. ubus提供了一个socket server:ubusd。因此开发者不需要自己实现server端。
- 2. ubus提供了创建socket client端的接口,并且提供了三种现成的客户端供用户直接使用:
1) 为shell脚本提供的client端。
2) 为lua脚本提供的client接口。
3) 为C语言提供的client接口。
可见ubus对shell和lua增加了支持,后面会介绍这些客户端的用法。
- 3. ubus对client和server之间通信的消息格式进行了定义:client和server都必须将消息封装成json消息格式。
- 4. ubus对client端的消息处理抽象出“对象(object)”和“方法(method)”的概念。一个对象中包含多个方法,client需要向server注册收到特定json消息时的处理方法。对象和方法都有自己的名字,发送请求方只需在消息中指定要调用的对象和方法的名字即可。
使用ubus时需要引用一些动态库,主要包括:
- libubus.so:ubus向外部提供的编程接口,例如创建socket,进行监听和连接,发送消息等接口函数。
- libubox.so:ubus向外部提供的编程接口,例如等待和读取消息。
- libblobmsg.so,libjson.so:提供了封装和解析json数据的接口,编程时不需要直接使用libjson.so,而是使用libblobmsg.so提供的更灵活的接口函数。
ubus中各组件的关系如下图所示:
使用ubus进行进程间通信不需要编写大量代码,只需按照固定模式调用ubus提供的API即可。在ubus源码中examples目录下有一些例子可以参考。在我的另一篇文章中,通过代码实例说明了ubus提供的三种进程间通信的方式点击打开链接。
2. ubus的实现原理
下面以一个例子说明ubus的工作原理:
下图中,client2试图通过ubus修改ip地址,而修改ip地址的函数在client1中定义。
client2进行请求的整个过程为:
1. client1向ubusd注册了两个对象:“interface”和“dotalk”,其中“interface”对象中注册了两个method:“getlanip”和“setlanip”,对应的处理函数分别为func1()和func2()。“dotalk”对象中注册了两个method:“sayhi”和“saybye”,对应的处理函数分别为func3()和func4()。
2. 接着创建一个client2用来与client1通信,注意,两个client之间不能直接通信,需要经ubusd(server)中转。
3. client2就是在前面讲到的shell/lua/C客户端。假设这里使用shell客户端,在终端输入以下命令:
ubus call interface setlanip ‘{“ip”:“10.0.0.1”, “mask”:24}’
ubus的call命令带三个参数:请求的对象名,需要调用的方法名,要传给方法的参数。
4. 消息发到server后,server根据对象名找到应该将请求转发给client1,然后将消息发送到client1,client1进而调用func2()接受参数并处理,如果处理完成后需要回复client2,则发送回复消息。
接下来介绍一下上述过程中,ubus内部的处理机制,虽然使用ubus进行进程间通信不需要关注这些实现细节,但有助于加深对ubus实现原理的理解。
下图中,client1注册对象和方法,其实可认为是服务提供端,只不过对于ubusd来讲是一个socket client。client2去调用client1注册的方法。
3. ubus的应用场景和局限性
ubus可用于两个进程之间的通信,并以类似json格式进行数据交互。ubus的常见场景为:
- “客户端--服务器”形式的交互,即进程A注册一系列的服务,进程B去调用这些服务。
- ubus支持以“订阅 -- 通知”的方式进行进程通信,即进程A提供订阅服务,其他进程可以选择订阅或退订该服务,进程A可以向所有订阅者发送消息。
由于ubus实现方式的限制,在一些场景中不适宜使用ubus:
- ubus用于少量数据的传输,如果数据量很大或是数据交互很频繁,则不宜用ubus。经过测试,当ubus一次传输数据量超过60KB,就不能正常工作了。
- ubus对多线程支持的不好,例如在多个线程中去请求同一个服务,就有可能出现不可预知的结果。
- 不建议递归调用ubus,例如进程A去调用进程B的服务,而B的该服务需要调用进程C的服务,之后C将结果返回给B,然后B将结果返回给A。如果不得不这样做,需要在调用过程中避免全局变量的重用问题。
4. ubus源码简析
下面介绍一下ubusd和ubus client工作时的代码流程,这里为了便于理解,只介绍大致的流程,欲了解详细的实现请读者自行阅读源码。
4.1 ubusd工作流程
ubusd 的初始化所做的工作如下:
1. epoll_create(32)创建出一个poll_fd。
2. 创建一个UDP unix socket,并添加到poll_fd的监听队列。
3. 进行epoll_wait()等待消息。收到消息后的处理函数定义如下:
static struct uloop_fd server_fd = {
.cb = server_cb,
};
即调用server_cb()函数。
4. server_cb()函数中的工作为:
(1)进行accept(),接受client连接,并为该连接生成一个client_fd。
(2)为client分配一个client id,用于ubusd区分不同的client。
(3)向client发送一个HELLO消息作为连接建立的标志。
(4)将client_fd添加到poll_fd的监听队列中,用于监听client发过来的消息,消息处理函数为client_cb()。
也就是说ubusd监听两种消息,一种是新client的连接请求,一种是现有的每个client发过来的数据。
当ubusd收到一个client的数据后,调用client_cb()函数的处理过程:
1. 先检查一下是否有需要向这个client回复的数据(可能是上一次请求没处理完),如果有,先发送这些遗留数据。
2. 读取socket上的数据,根据消息类型(数据中都指定了消息类型的)调用相应的处理函数,消息类型和处理函数定义如下:
static const ubus_cmd_cb handlers[__UBUS_MSG_LAST] = {
[UBUS_MSG_PING] = ubusd_send_pong,
[UBUS_MSG_ADD_OBJECT] = ubusd_handle_add_object,
[UBUS_MSG_REMOVE_OBJECT] = ubusd_handle_remove_object,
[UBUS_MSG_LOOKUP] = ubusd_handle_lookup,
[UBUS_MSG_INVOKE] = ubusd_handle_invoke,
[UBUS_MSG_STATUS] = ubusd_handle_response,
[UBUS_MSG_DATA] = ubusd_handle_response,
[UBUS_MSG_SUBSCRIBE] = ubusd_handle_add_watch,
[UBUS_MSG_UNSUBSCRIBE] = ubusd_handle_remove_watch,
[UBUS_MSG_NOTIFY] = ubusd_handle_notify,
};
例如,如果收到invoke消息,就调用ubusd_handle_invoke()函数处理。
这些处理函数可能是ubusd处理完后需要回发给client数据,或者是将消息转发给另一个client(如果发送请求的client需要和另一个client进行通信)。
3. 处理完成后,向client发送处理结果,例如UBUS_STATUS_OK。(注意,client发送数据是UBUS_MSG_DATA类型的)
4.2 client的工作流程
ubus call obj method的工作流程:
1. 创建一个unix socket(UDP)连接ubusd,并接收到server发过来的HELLO消息。
2. ubus call命令由ubus_cli_call()函数进行处理,先向ubusd发送lookup消息请求obj的id。然后向ubusd发送invoke消息来调用obj的method方法。
3. 创建epoll_fd并将client的fd添加到监听列表中等待消息。
4. client收到消息后的处理函数为ubus_handle_data(),其中UBUS_MSG_DATA类型的数据receive_call_result_data()函数协助解析。
被call的client的工作流程:
和ubus客户端的流程相似,只是变成了接受请求并调用处理函数。
进程通信
[openwrt] 使用ubus实现相关推荐
- ubus c语言例子,openwrt之ubus例子
好一个ic root@LEDE:/# ubus call test_ubus helloworld '{"id":1,"msg":"hi" ...
- 一点一滴分析LinkIt™ Smart 7688 webUI
LinkIt 7688提供了一个友好的登录界面,源代码可以在下面的连接下载到: https://github.com/MediaTek-Labs/linkit-smart-7688-webUI 翻译文 ...
- OpenWrt开发必备软件模块——系统总线ubus
一.ubus模块介绍 OpenWrt 提供了一个系统总线ubus,它类似于Linux桌面操作系统的d-Bus,目标是提供系统级的进程间通信(IPC)功能.ubus在设计理念上与d-Bus基本保持一致, ...
- 十 ubus安装编译
ubus是openwrt平台上的一种进程间通信机制,用起来非常方便,且移植性强,符合设计中的迪米特原则,可以异步开发.因此被扩展到很多软件中,通用性好,不用重造轮子,也方便与其它人共同开发.我们自己在 ...
- i.mx6ul 移植Openwrt
一直在使用Openwrt很多年,从路由到IOT终端,网关等,相对于其他开发环境或者厂家SDK来说,openwrt确实很便捷,其内部的Lua,ubox,ubus,rpc等一些机制,能在开发中带来很大的便 ...
- ubuntu编译ubus及相关依赖库
ubus简介: ubus全称为:openwrt micro bus. 引言: 为了在OpenWrt中提供守护进程和应用程序间的通讯,开发了ubus项目工程.它包含了守护进程.库以及一些额外的帮助程序. ...
- openwrt系统理解
本文章纯属记录自己理解过程,理解有误请大佬指出.新手小白求一键三连(*╹▽╹*) ------------------------------------------- 老规矩,介绍: OpenWrt ...
- openwrt php 编译环境,在linux下修改编译网件WNDR3700v4的Openwrt固件,支持128MB NAND
Openwrt官方的网件WNDR3700v4固件(15.05.1)不能完整利用128MB NAND的空间,刷完后只剩13MB了,网上说还有96MB左右空闲着,只能修改Makefile自己重新编译固件, ...
- OpenWrt支持usb tethering
OpenWrt支持usb tethering 一.概述 OpenWrt支持usb tethering的应用场景主要是,手机打开usb网络共享(Android)或个人热点(iOS),经过USB的连接,使 ...
最新文章
- 99_leetcode_Best Time to Buy and sell Stock
- MDA模型定义及扩展
- Qt 中容器类型的控件
- 如何自定义Tableau 调色板
- java foreach break_Java8中的foreach跳出循环break/return
- HDU 6330--Visual Cube(构造,计算)
- 在网页中实现:手势解锁密码
- php 公众号 群发,php实现微信公众号无限群发
- SpringBoot:上传图片到Linux服务器
- PHP实现发送邮件功能代码|PHP怎么实现QQ邮件发送|Php发送邮件代码
- Linux操作系统学习笔记(十)内存管理之内存映射
- linux 5.5安装万兆网卡驱动,CentOS下安装网卡驱动
- Qt Creator不同Qt版本切换
- 编玩边学——高新科技启蒙教育,让程序编写铸就高新科技能手
- Linux常用命令详解 ls -l命令详解
- 在Visual Studio 2010/2012/2013/2015上使用C#开发Android/IOS安装包和操作步骤
- php读取淘宝数据包csv文件 unicode ucs-2 utf-16 中文乱码问题解决
- 【杂项】通过Excel为字符串产生条码
- python用于pmc排产可以吗_PMC-你最想要的实用干货来了!
- 计算机操作工中级理论,计算机操作员中级理论知识复习题及答案.doc