了解openwrt libubox library
及測試範例
更新記錄
item | note |
---|---|
20161130 | 第一版 |
目錄
openwrt libubox
libubox主要提供一下两种功能:
1、提供一套基于事件驱动的机制。
2、提供多种开发支持接口。(如:链表、kv链表、平衡查找二叉树、md5、json)使用libubox开发的好处有如下几点:
1、可以使程序基于事件驱动,从而可实现在单线程中处理多个任务。
2、基于libubox提供的开发API可以加快开发进度的同事提高程序的稳定性。
3、能更好的将程序融入openwrt的架构中,因为新的openwrt的很多应用和库都基于libubox开发的
libubox.so提供下例工具
- openwrt libubox
utils - misc libubox utility functions
1
2
3
4- calloc_a(size_t len, [void **addr, size_t len,...], NULL)
allocate a block of memory big enough to hold multiple aligned objects.
- b64_encode
- b64_decodeusock - socket helper functions
1
usock(int type, const char *host, const char *service);
uloop - event loop implementation
- Uloop is a loop runner for i/o.
- The fd management part is set up with the uloop_fd struct, just adding the fd and the callback function you want called when an event arises.
- The timeout management part is mostly prepared to do simple things,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18typedef void (*uloop_fd_handler)(struct uloop_fd *u, unsigned int events);
typedef void (*uloop_timeout_handler)(struct uloop_timeout *t);
typedef void (*uloop_process_handler)(struct uloop_process *c, int ret);
int uloop_fd_add(struct uloop_fd *sock, unsigned int flags);
int uloop_fd_delete(struct uloop_fd *sock);
int uloop_timeout_add(struct uloop_timeout *timeout);
int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
int uloop_timeout_cancel(struct uloop_timeout *timeout);
int uloop_timeout_remaining(struct uloop_timeout *timeout);
int uloop_process_add(struct uloop_process *p);
int uloop_process_delete(struct uloop_process *p);
int uloop_init(void);
void uloop_run(void);
void uloop_done(void);
blob ,library for generating/parsing tagged binary data
example
ustream-example 測試
帶起ustream-example
1
2
3
4~ # netstat -tpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:10000 0.0.0.0:* LISTEN 908/ustream-example測試
1
2
3#cat t1
111
#nc 127.0.0.1 10000 < t1log
1
2
3
4/test # ./ustream-example
New connection
eof!, pending: 0, total: 4
Connection closed
ustream-example 程式流程
run_server
server_cb
libubox
uloop
uloop主要工能有下例3個
- 文件描述符觸發事件的監控 (即uloop_run_events)
循環調用epoll_wait 監相應的觸發事件文件描述符fd - timeout定時器處理(即uloop_process_timeouts)
- 當前進程的子進程的維護(即uloop_handle_processes)
當某一個進程第一次調用uloop_run時,註冊sigchld和sigint信號
uloop_timeout
循環獲取當前時間,把超時的timeout處理掉,
有一條timeout鍊表在維護(即static struct list_head timeouts)uloop_process
循環檢測是否收到一個sigchld信號,如果收到,刪除對應的子進程,
有一條process子進程鍊表在維護(即static struct list_head processes )libubox function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23uloop_fd_add
註冊一個新描述符到事件處理循環
uloop_fd_delete
從事件處理循環中銷毀指定描述符
uloop_timeout_add
註冊一個新定時器
uloop_timeout_set
設置定時器超時時間(毫秒),並添加
uloop_timeout_cancel
銷毀指定定時器
uloop_timeout_remaining
獲取定時器還剩多長時間超時
uloop_process_add
註冊新進程到事件處理循環
uloop_process_delete
從事件處理循環中銷毀指定進程
uloop程序
uloop 是 libubox 的一部份,其功能包括
timeout:再多久執行指定函數
執行 child process,結束時執行指定的函數
fd 事件發生時執行指定函數。(使用 kqueue 或 epoll)
uloop_init
建立poll_fd
epoll_create(32)uloop_fd_add
註冊一個新描述符到事件處理循環uloop_run
文件描述符觸發事件的監控 (即uloop_run_events)
uloop_init
uloop_init
FD_CLOEXEC
- 如何避免fd 被多個子行程繼承
若程式中有exec(即fork等行為)產生子程序,此時子程序開啟的fd量會多1個(即父程序)
在父程序中設定FD_CLOEXEC,表示當exec時設定父程序的fd為close
It sets the close-on-exec flag for the file descriptor, which causes the file descriptor to be automatically (and atomically) closed when any of the exec-family functions succeed.
- 如何避免fd 被多個子行程繼承
uloop_fd_add
uloop_fd_add
註冊一個新描述符到事件處理循環uloop_fd_delete
從事件處理循環中銷毀指定描述符
uloop_run
- uloop_run
uloop_get_next_timeout
- 取得timeout時間
uloop_run_events
- 設定epoll_wait及timeout
- 確認是否有fd要執行
ustream
ustream - library for stream buffer management
ustream_fd_init(struct ustream_fd *s, int fd);
ustream_fd_init: create a file descriptor ustream (uses uloop)
ustream_fd_init
- ustream_fd_init
ustream_uloop_cb
- ustream_fd_read_pending
- while(1)
- read(sf->fd.fd,
- if (!s->eof) ustream_state_change(s) && return
- ustream_fill_read
- if (s->notify_read) s->notify_read(s, n);
ustream_state_change_cb
- ustream_state_change_cb
epoll
epoll
- epoll - I/O event notification facility
- Three system calls are provided to set up and control an epoll set: epoll_create, epoll_ctl, epoll_wait
epoll之所以高效,是因為epoll將用戶關心的文件描述符放到內核里的一個事件表中,而不是像select/poll每次調用都需要重複傳入文件描述符集或事件集。比如當一個事件發生(比如說讀事件),epoll無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入就緒隊列的描述符集合就行了
-
- epoll是linux系統最新的處理多連接的高效率模型
- 工作在兩種方式
- EPOLLLT方式 (level-triggered模式),EPOLLLT是系統默認
於level-triggered模式下,epoll_wait在事件狀態未變更前將不斷被觸發 - EPOLLET方式 (edge-triggered模式)
epoll_wait僅會在新的事件首次被加入epoll 物件時返回
- wiki epoll
舉例來說,倘若有一個已經於epoll註冊之管線接獲資料,epoll_wait將返回,並發出資料讀取的信號。現假設緩衝區的資料僅有部份被讀取並處理,在level-triggered模式下,任何對epoll_wait之呼叫都將即刻返回,直到緩衝區中的資料全部被讀取;然而,在edge-triggered的情境下,epoll_wait僅會於再次接收到新資料(亦即,新資料被寫入管線)時返回。
參考
- openwrt libubox
- 如何避免fd 被多個子行程繼承
- What does the FD_CLOEXEC fcntl() flag do?
- epoll(4) - Linux man page
- Using epoll() For Asynchronous Network Programming
- wiki epoll
- epoll模型的EPOLLLT模式和EPOLLET模式比較
libubox說明文章