ubus是OpenWrt中的进程间通讯机制,相似于桌面版linux的dbus,Android的binder。ubus至关于简化版的dbus,ubus基于unix socket实现,socket绑定到一个本地文件,具备较高的效率;css
unix socket是C/S模型,创建一个socket链接,server端和client端分别要作以下步骤:
1. 创建一个socket server端,绑定到一个本地socket文件,监听client的链接;
2. 创建一个或多个socket client端,链接到server端;
3. client端和server端相互发送消息;
4. client端或server端收到对方消息后,针对具体消息进行相应处理。linux
以下图所示:
web
ubus一样基于这套流程,其中ubusd实现server,其余进程实现client,例如ubus(cli)、netifd、procd;
两个client通讯须要经过server转发。shell
ubusd
ubusd做为ubus的server端,已经由OpenWrt实现好了,不须要作任何修改,下面来分析一下ubusd的工做流程;
1. 经过usock来建立server端socket,且socket bind到文件”/var/run/ubus.sock”,开启listen,等到client的链接;
2. 将socket添加到uloop中poll,触发条件是read,也就是说server socket可读,则触发poll回调server_cb,server_fd的回调函数是server_cb; ruby
static struct uloop_fd server_fd = {
.cb = server_cb,
};
server_cb中经过accept来接受client的链接,套接字函数accept执行退出以后会建立一个新的socket,新的socket的fd为accept函数值,而旧的socket不变,也就是accept以后,server端存在两个socket了,旧的socket依然用来listen,新的socket与client创建pair,用于和client的通信;
根据新的socket的fd(int client_fd)来构建一个ubus_client对象,ubus_client的uloop回调函数是client_cb,将ubus_client插入到avl树中(struct avl_tree clients),每一个向ubusd注册的client都在对应到avl树中的一个ubus_client;
ubusd_send_hello,向client端的socket发送一个字符串”hello”;
将ubus_client中的socket fd添加到uloop中去轮询监听,触发条件是read,回调函数是client_cb,也就是client发消息到server,则触发回调client_cb;
client_cb经过write或sendmsg来发消息给client,经过read或recvmsg来接收来自client的消息,ubusd_proto_receive_message根据接收的不一样消息类型作不一样的处理,以下所示