這篇文章能夠算是我在 GitHub 上一個工程的設計概要了。簡要說明了該工程的設計思路以及技術要點。git
本文章純原創,沒有參考資料。不過有設計過程當中記錄下的相關文章:程序員
使用 pipe 在程序正文中捕獲和處理信號github
本文地址:http://www.javashuo.com/article/p-zyoylygv-cx.htmlsegmentfault
總所周知,在 Linux 中實現異步 I/O,適用的系統 API 就是 epoll
。這裏主要包括 epoll_ctl()
和 epoll_wait()
兩個函數。前者配置各個文件描述符在 epoll 裏的機制,然後者則是關鍵的阻塞調用。服務器
這個工程,就是基於 epoll
,實現相似於 libevent
的異步 I/O 庫。架構
函數的具體用法能夠參照 man 頁,或者工程的 AMCEpoll.c 源文件的 _dispatch_main_loop()
函數。異步
早期打算通用的寫一個進程間通訊庫。通訊庫想要使基於異步 I/O 來作,又不想只是使用裸的 epoll。想起本身對異步 I/O 的原理也算是大體瞭解了,就本身研究着寫一個。目前已經大體完成的 AMCEpoll
並無通過嚴格的測試驗證,更多地像是一個學習工程,或者說是課後做業同樣。就像 Andrew S. Tanenbaum 教授的 Minix
相似哈。函數
不過這個庫是瞄準了實用來設計的。若是要面向可靠的話,建議用開源的 libevent
來構建;若是以爲 libevent 太大了,則推薦 libev
;若是以爲 libev
的開發者太少,不靠譜的話,那麼能夠用 libuv
。若是須要有本身知識產權的產品的話,那麼,能夠本身設計一個——這也就是我開發這個庫的初衷。oop
公共的 API 都在 AMCEpoll.h 文件中。各函數的說明以下:學習
struct AMCEpoll
至關於 libevent 的 「event base」。這是整個 AMCEpoll 對象,每個對象可執行一個事件循環(event loop)。
struct AMCEpollEvent
至關於 libevent 的 「event」。與 libevent 不一樣的是,每個 event 能夠從某個 base 中分離,再加入到另外一個 base 裏面去。不過實際上應該沒有這樣的需求,只是說個人程序架構容許這麼作。
AMCEpoll 支持三種事件:
AMCEpoll_New()
建立、初始化並返回一個 AMCEpoll 對象。其中參數 pollSize 指的是 epoll_wait()
函數中的 maxevents
參數。
AMCEpoll_Free()
銷燬一個 AMCEpoll 對象。若是對象中還有事件存在,而且事件關注了 EP_EVENT_FREE
事件,則會收到對應的回調。
不能在 event loop 中調用。
AMCEpoll_NewEvent()
建立並返回一個事件(AMCEpollEvent)對象。各參數說明以下:
AMCEpoll_FreeEvent()
銷燬一個事件。若是事件關注了 EP_EVENT_FREE
,那麼會在此時收到回調。程序員能夠在這個地方執行一些庫之外的清理工做,好比 close(fd)
之類的。
若是該事件已經加入到某個 AMCEpoll 對象中,那麼這個函數會出錯。若是要避免這個問題,建議使用 AMCEpoll_DelAndFreeEvent()
函數。
AMCEpoll_AddEvent()
將某個 AMCEpollEvent 對象加入到 AMCEpoll 中,這樣才能在事件循環中關注這個對象上的事件。
AMCEpoll_DelEvent()
將已經加入到 AMCEpoll 的時間分離開來,成爲 「孤魂野鬼」 狀態。
AMCEpoll_DelAndFreeEvent()
Del 和 Free 兩個函數的結合。
AMCEpoll_SetEventTimeout()
,AMCEpoll_GetEventTimeout()
從新設置或者獲取一個事件的超時時間。這隻有在建立時,添加了 EP_EVENT_TIMEOUT
事件,纔會有效。
AMCEpoll_Dispatch()
在當前線程啓動事件循環。當沒有事件註冊在案的時候,event loop 會退出,也就是這個函數會返回。
AMCEpoll_LoopExit()
退出事件循環。若是這個函數在 event loop 外調用,那麼 AMCEpoll 會在走完下一次 event chain 以後退出;若是在 event loop 中間調用,則 AMCEpoll 會走完當前 event chain 以後退出。Event chain 的原理,在後文說明。
事件類型就是 event_t
數據類型,聲明以下:
enum { EP_EVENT_READ = (1 << 0), EP_EVENT_WRITE = (1 << 1), EP_EVENT_ERROR = (1 << 2), EP_EVENT_FREE = (1 << 3), EP_EVENT_TIMEOUT = (1 << 4), EP_EVENT_SIGNAL = (1 << 5), EP_MODE_PERSIST = (1 << 8), /* only used when adding events */ EP_MODE_EDGE = (1 << 9), /* only used when adding events */ };
當建立事件的時候,上述全部的類型均可以使用;而當回調的時候,回調函數只可能接收到 EV_EVENT_XXX
類型的值。三種 AMCEpollEvent 所支持的具體類型以下:
———— | _READ | _WRITE | _ERROR | _FREE | _TIMEOUT | _SIGNAL | _PERSIST | _EDGE |
---|---|---|---|---|---|---|---|---|
文件事件 | O | O | O | O | O | . | O | O |
信號事件 | . | . | O | O | O | O | O | O |
超時事件 | . | . | . | O | O | . | . | . |
具體的參數說明以下:
EP_EVENT_READ
:讀事件。若是出現這個事件類型,則視爲文件事件。EP_EVENT_WRITE
:讀事件。若是出現這個事件類型,則視爲文件事件。EP_EVENT_ERROR
:通常是系統調用出錯。保留。EP_EVENT_FREE
:「銷燬」 事件。當調用 AMCEpoll_FreeEvent()
的時候觸發。EP_EVENT_TIMEOUT
:超時事件EP_EVENT_SIGNAL
:信號事件。若是出現這個事件類型,則視爲信號事件。不得與文件事件同時存在。EP_MODE_PERSIST
:持續事件。當一次回調(除了 free)完成後,程序會自動將事件及其超時配置加入到 event loop 中。固然,若是程序手動 add 的話,也是能夠的,只是不必。EP_MODE_EDGE
:邊緣觸發模式。若是使用這個模式的話,只在出現事件纔會觸發回調。
基本的使用流程和 libevent 和 libev 很是相似,能夠參照個人這篇文章:《使用 libev 構建 TCP 響應服務器的簡單流程》
好比一個 UDP 事件基本流程:
recvfrom()
其餘事件的用法,則能夠參照工程內的 test_server.c 文件。這個文件建立了三種事件:
SIGINT
和 SIGQUIT
。監聽到前者時,退出 AMCEpoll 事件循環。監聽到後者時,打印調試信息。
下一篇會說明一下工程的實現篇。文章還沒有完成,敬請期待。