openwrt 常用库用法
来源:互联网 发布:阿里云怎么提现 编辑:程序博客网 时间:2024/06/12 07:12
openwrt常用库用法
libubox
1.1.概述
libubox是openwrt的一个基础库,openwrt下大部分应用都是基于它开发的(ubus、uhttpd、uci等)。
libubox主要提供了两类功能:
[1].一套完整的基于事件驱动的机制
[2].多个常用的功能模块(链表、avl树、json、消息传输单元、md5)
1.2.基于事件驱动机制
基于事件驱动机制是libubox的核心部分,这套机制主要实现了一套通用的非阻塞I/O多路复用(epoll)平台。
以下是这部分的常用API整理
API
用法
intuloop_init(void)
创建epoll句柄
voiduloop_done(void)
注销epoll模块
intuloop_fd_add(struct uloop_fd *sock,unsigned int flags)
将需要监听的fd以及要监听的事件注册到epoll(默认拥有水平触发和非阻塞的特性)
@sock-需要被epoll监听的fd管理块,主要记录了自己创建的fd、事件处理回调
@flags-监听的事件类型,必须至少包含ULOOP_READ或ULOOP_WRITE或ULOOP_PRI(这个是本人补丁追加的)
intuloop_fd_delete(struct uloop_fd *sock)
从epoll监听池中删除指定的fd
@sock-要从监听池中删除的fd管理块
voiduloop_run(void)
事件驱动模型的主循环,在这里面进行[等待事件/超时->处理事件/超时->等待事件]的循环,通过信号退出
intuloop_timeout_set(struct uloop_timeout *timeout,int msecs)
给定时器设置一个超时值,并激活
@timeout-定时器模块,主要记录了超时值、超时处理函数
@msecs-超时值,单位ms
intuloop_timeout_cancel(struct uloop_timeout *timeout)
关掉定时器
@timeout-要关掉的定时器模块
代码示范(未处理返回值):
voidrecv_handler(struct uloop_fd *h,uint32_t events)
{
/*do your recv handler*/
}
voidtimeout_handler(struct uloop_timeout *timer)
{
/*do your timeout handler*/
}
intmain(int argc,char **argv)
{
structuloop_fd myfd;
structuloop_timeout mytimer;
uloop_init();
myfd.fd= socket(PF_PACKET,SOCK_RAW,htons(ETH_P_PAE));
myfd.cb= recv_handler;
uloop_fd_add(&myfd);
mytimer.cb=timeout_handler;
uloop_timeout_set(&mytimer,100);
uloop_run();
uloop_fd_delete(&myfd);
close(myfd.fd);
uloop_timeout_cancel(&mytimer);
uloop_done();
return0;
}
1.3.链表
libubox的链表是完全参照内核链表的设计理念,跟普通链表的区别在于,它不是将数据结构塞入链表,而是将链表节点塞入数据结构。
以下是链表的数据结构:
structlist_head {
structlist_head *next;
structlist_head *prev;
};
structlist_head就是抽象出来的链表模块,使用方法就是将其插入到自定义的结构中,范例如下:
structfox {
intlen;
intweight;
structlist_head list;
};
上述结构中,fox中的list.next指向下一个元素,list.prev指向前一个元素。
通常,对链表的管理还需要一个标准的索引指针指向整个链表,即链表的头指针,这个特殊的头指针事实上也就是一个常规的list_head.
以下是链表操作API:
LIST_HEAD(name)
创建并初始化链表头节点(前驱和后继都指向自己)
staticinline void INIT_LIST_HEAD(struct list_head *list)
初始化链表头节点
staticinline void list_empty(const struct list_head *head)
判断链表是否为空,空返回1,非空返回0
staticinline void list_del(struct list_head *entry)
删除指定节点
staticinline void list_add(struct list_head *new,struct list_head *head)
节点从头部插入链表
staticinline void list_add_tail(struct list_head *new,struct list_head*head)
节点从尾部插入链表
list_entry(ptr,type,field)
根据链表模块地址反推得到父结构地址
@ptr-链表模块地址(比如上面的“&fox.list”)
@type-父结构类型(比如上面的”structfox”)
@field-父结构中链表模块的名字(比如上面的”list”)
list_for_each_entry(p,h,field)
遍历链表的父结构(不支持遍历中删除操作)
@p-遍历出来的父结构指针
@h-链表头节点指针
@field-父结构中链表模块的名字
list_for_each_entry_safe(p,n,h,field)
遍历链表的父结构(可以支持遍历中删除操作)
@n-备份指针
备注:操作链表(添加、删除、移动、合并)的时间复杂度为O(1),意味着无论操作的链表大小以及参数如何,他们都是在恒定时间内完成的;
遍历链表的时间复杂度为O(n),n是链表包含的节点数目,意味着遍历时间跟节点数量呈线性关系
1.4.数据传输单元
libubox提供了一套通用的数据传输机制,数据类型可以是
enumblobmsg_type {
BLOBMSG_TYPE_UNSPEC,
BLOBMSG_TYPE_ARRAY,
BLOBMSG_TYPE_TABLE,
BLOBMSG_TYPE_STRING,
BLOBMSG_TYPE_INT64,
BLOBMSG_TYPE_INT32,
BLOBMSG_TYPE_INT16,
BLOBMSG_TYPE_INT8,
};
其中array和table两种数据类型还支持嵌套使用。
structblob_buf表示一个完整的数据传输单元,这个数据结构是这套数据传输机制的核心,需要注意的是,blob_buf使用完后一定要调用blob_buf_free销毁,特别是当定义成局部变量时!
以下是这套数据传输机制的常用API整理:
intblob_buf_init(struct blob_buf *buf,int id)
blob_buf初始化,也可以理解为复位
@buf-数据传输单元
@id-数据类型
voidblob_buf_free(struct blob_buf *buf)
注销blob_buf,实际就是释放blob_buf使用过程中申请的空间
staticinline const char *blobmsg_name(const struct blob_attr *attr)
获取消息的名字
staticinline int blobmsg_type(const struct blob_attr *attr)
获取消息的类型
staticinline int blobmsg_len(const struct blob_attr *attr)
获取消息值长度
staticinline uint8_t blobmsg_get_u8(struct blob_attr *attr)
获取uint8_t类型的消息值
staticinline uint16_t blobmsg_get_u16(struct blob_attr *attr)
获取uint16_t类型的消息值
staticinline uint32_t blobmsg_get_u32(struct blob_attr *attr)
获取uint32_t类型的消息值
staticinline uint64_t blobmsg_get_u64(struct blob_attr *attr)
获取uint64_t类型的消息值
staticinline char *blobmsg_get_string(struct blob_attr *attr)
获取字符串类型的消息值
staticinline int blobmsg_add_u8(struct blob_buf *buf,const char*name,uint8_t val)
添加一条uint8_t类型的消息
@buf-数据传输单元
@name-消息名
@val- uint8_t类型的消息值
staticinline int blobmsg_add_u16(struct blob_buf *buf,const char*name,uint16_t val)
添加一条uint16_t类型的消息
@buf-数据传输单元
@name-消息名
@val- uint16_t类型的消息值
staticinline int blobmsg_add_u32(struct blob_buf *buf,const char*name,uint32_t val)
添加一条uint32_t类型的消息
@buf-数据传输单元
@name-消息名
@val- uint32_t类型的消息值
staticinline int blobmsg_add_u64(struct blob_buf *buf,const char*name,uint64_t val)
添加一条uint64_t类型的消息
@buf-数据传输单元
@name-消息名
@val- uint64_t类型的消息值
staticinline int blobmsg_add_string(struct blob_buf *buf,const char*name,const char *string)
添加一条字符串类型的消息
@buf-数据传输单元
@name-消息名
@val-字符串类型的消息值
staticinline void *blobmsg_open_array(struct blob_buf *buf,const char*name)
开启一个array类型的消息
@buf-数据传输单元
@name-消息名
返回值-指向这个开启的array,也就是下面用到的”cookie”
staticinline void blobmsg_close_array(struct blob_buf *buf,void *cookie)
关闭一个array类型的消息
@buf-数据传输单元
@cookie-指向这个开启的array
staticinline void *blobmsg_open_table(struct blob_buf *buf,const char*name)
开启一个table类型的消息
@buf-数据传输单元
@name-消息名
返回值-指向这个开启的array,也就是下面用到的”cookie”
staticinline void blobmsg_close_table(struct blob_buf *buf,void *cookie)
关闭一个table类型的消息
@buf-数据传输单元
@cookie-指向这个开启的table
备注:完成一条array或table消息的创建需要成对调用开启、关闭两个函数。
1.5. json
暂略
1.6. avl树
暂略
1.7.md5
暂略
1.8socket
目前只封装了unix-sock和inet-sock,个人觉得比较鸡肋,暂不分析。
libubus
ubus是openwrt引入的一个消息总线,类似于桌面linux系统中的dbus,其设计理念也基本一致,就是提供系统级的IPC和RPC。
2.1基本原理
整套ubus基于libubox库实现,通信的基础是unix-sock,ubus提供了一个后台服务器ubusd进行所有ubus消息的中转处理。
所以,对于开发者来说,关注点就全放在客户端。ubus将客户端分为2种角色:
服务提供者
服务消费者
备注:当然某个客户端既可以是一些服务的提供者,同时又可以是另一些服务的消费者
ubus对其上面承载的消息格式进行了定义:采用json消息格式。
ubus将服务抽象成为“对象”和“方法”,一个对象可以包含多个方法。“对象”必须先注册到ubus后台服务器,才能被消费者调用。
ubus支持以“阅订-通知”的方式进行进程通信,即进程A提供阅订服务,其他进程可以选择阅订或退订该服务,进程A就可以向所有阅订者广播推送通知。
2.1.C接口使用方法
libubus就是其C接口库,以下是常用API整理:
structubus_context *ubus_connect(const char *path)
创建ubus客户端并发起连接
@path- ubus后台服务器socket地址,默认就是/var/run/ubus.sock
返回值-成功则返回一个ubus客户端控制块
voidubus_free(struct ubus_context *ctx)
注销ubus客户端
staticinline void ubus_add_uloop(struct ubus_context *ctx)
ubus客户端注册到libubox库epoll监听池中
intubus_add_object(struct ubus_context *ctx,struct ubus_object *obj)
ubus服务提供者调用,用来注册一个“对象”
@ctx- ubus客户端控制块
@obj-要注册的对象控制块
intubus_lookup_id(struct ubus_context *ctx,const char *path,uint32_t*id)
ubus服务消费者调用,根据“对象”名查找对应的id号
@ctx- ubus客户端控制块
@path-对象名
@id-记录查到的对象id
intubus_register_subscriber(struct ubus_context *ctx,structubus_subscriber *obj)
ubus客户端注册一个阅订模块,后续阅订服务用
@ctx- ubus客户端控制块
@obj-要注册的阅订控制块
intubus_invoke(struct ubus_context *ctx,uint32_t obj const char*method,struct blob_attr *msg,ubus_data_handler_t cb,void*priv,int timeout)
ubus服务消费者调用,用于调用一个指定服务(同步调用)
@ctx- ubus客户端控制块
@obj-对象id
@method-指定“对象”包含的某个“方法”名
@msg-具体的调用消息
@cb-收到返回消息的处理函数
@priv-用户自定义项,cb函数中可以使用
@timeout-本次调用的超时时间
intubus_invoke_async(struct ubus_context *ctx,uint32_t obj const char*method,struct blob_attr *msg,struct ubus_request *req)
ubus服务消费者调用,用于调用一个指定服务(异步调用)
@ctx- ubus客户端控制块
@obj-对象id
@method-指定“对象”包含的某个“方法”名
@msg-具体的调用消息
@req-用来记录本次异步调用的相关信息
intubus_send_reply(struct ubus_context *ctx,struct ubus_request_data*req,struct blob_attr *msg)
ubus服务提供者调用,用于回复服务消费者的调用请求
@ctx- ubus客户端控制块
@req-用来记录本次调用的相关信息
@msg-具体的回复消息
intubus_notify(struct ubus_context *ctx,struct ubus_object *obj,constchar *type,struct blob_attr *msg,int timeout)
ubus客户端向所有阅订者广播推送通知
@ctx- ubus客户端控制块
@obj-自身对象控制块
@type-通知类型名
@msg-具体的通知消息
@timeout-本次通知的超时值
2.2使用范例(不考虑异常情况)
2.2.1作为服务提供者
enum{
TEST_HELLO,
_MAX_TEST,
};
staticstruct ubus_context *ctx;
staticconst struct blobmsg_policy policy[] = {
[TEST_HELLO]{.name= “test_hello”, .type = BLOBMSG_TYPE_STRING},
};
staticint test_handler(struct ubus_context *ctx,struct ubus_object*obj,struct ubus_request_data *req,const char *method,structblob_attr *msg)
{
/*do your handler*/
}
staticstruct ubus_method methods[] = {
UBUS_METHOD(“test_hello”,test_handler,policy),
};
staticstruct ubus_object_type object_type =UBUS_OBJECT_TYPE(“test”,methods);
staticstruct ubus_object object = {
.name= “test”,
.type= &object_type,
.methods= methods,
.n_methodds= ARRAY_SIZE(methods),
};
intmain(int argc,char **argv)
{
uloop_init();
ctx= ubus_connect(NULL);
uloop_add_uloop(ctx);
ubus_add_object(ctx,&object);
uloop_run();
ubus_free(ctx);
uloop_done();
return0;
}
2.2.2作为服务消费者
staticstruct blob_buf b;
staticvoid reply_handler(struct ubus_request *req,int type,struct blob_attr*msg)
{
/*do your handler*/
}
staticint call_server(struct ubus_context *ctx)
{
intid;
ubus_lookup_id(ctx,”test”,&id);
blob_buf_init(&b,0);
blobmsg_add_string(&b,”name”,”value”);
intret = -1;
returnubus_invoke(ctx,id,”test_hello”,b.head,reply_handler,&ret,1000);
}
intmain(int argc,char **argv)
{
uloop_init();
ctx= ubus_connect(NULL);
uloop_add_uloop(ctx);
call_server();
uloop_run();
ubus_free(ctx);
uloop_done();
return0;
}
2.2.3作为阅订者
staticstruct ubus_subscriber event;
staticvoid remove_handler(struct ubus_context *ctx,struct ubus_subscriber*s,uint32_t id)
{
/*doyour handler*/
}
staticint event_handler(struct ubus_context *ctx,struct ubus_object*obj,struct ubus_request_data *req,const char *method,structblob_attr *msg)
{
/*doyour handler*/
}
intmain(int argc,char **argv)
{
uloop_init();
ctx= ubus_connect(NULL);
uloop_add_uloop(ctx);
ubus_register_subscriber(ctx,&event);
event.remove_cb= remove_handler;
event.cb= event_handler;
ubus_lookup_id(ctx,”test”,id);
ubus_subscribe(ctx,&event,id);
ubus_run();
ubus_free(ctx);
uloop_done();
return0;
}
2.2.4作为通知方
intmain(int argc,char **argv)
{
uloop_init();
ctx= ubus_connect(NULL);
uloop_add_uloop(ctx);
ubus_add_object(ctx,&object);
ubus_notify(ctx,&object,”notify”,NULL,-1);
ubus_run();
ubus_free(ctx);
uloop_done();
return0;
}
3.libuci
暂略
- openwrt 常用库用法
- openwrt常用网站汇总
- openwrt 的常用指令
- openwrt常用功能编译选项
- Openwrt常用烧写命令
- Boost常用库用法
- Boost常用库用法
- Openwrt常用烧写命令 (tftp)
- openwrt 搜索库
- openwrt库依赖问题
- openwrt
- OpenWRT
- openWRT
- openWRT
- openwrt
- openwrt
- Openwrt
- openwrt
- txt数据导入mysql错误Invalid Date: ' ' is not a valid datetime(或int value等)
- javascript --string对象常规操作 增、删、改、查。
- Java输入外挂
- Qt之启动外部程序(使用参数很全面,还使用了setProcessChannelMode)
- getenv、setenv函数(获取和设置系统环境变量) 与 环境变量
- openwrt 常用库用法
- LeetCode 48 Rotate Image
- [SQL]只更新表中某一部分数据的实现方法
- eclipse使用技巧
- TLV 解析(Java)
- ReentrantReadWriteLock的简单使用
- ffmpeg Intel硬件加速总结
- JAVA高级工程师课程笔记整理——(七)Mysql
- AndroidStudio 出现问题