libevent源码学习-----阅读心得
框架設計思路
- libevent使用統一事件源將所有問題都轉化為event,比如將套接字/信號/描述符都在內部轉化為event,由相應的io多路復用函數進行監控。
- 為了提供對超時event的支持,libevent將所有的超時時間都轉化為絕對時間,這就將雜亂無章的超時event有序管理起來,同時采用最小堆存儲那些具有超時時間的event,這樣當堆頂event沒有超時,那么堆中所有event都不會超時。
- libevent采用Reactor反應器模式來處理所有的event,內部使用io多路復用進行監控,又因為需要由libevent主動調用用戶的回調函數,所以libevent內部大量使用函數指針保存和調用用戶提供的回調函數,其實就是利用函數指針實現多態
- 是出現一個激活event就調用對應回調函數,還是先將所有激活event存在一起,統一調用。顯然更好的是后者,因為可以對激活event進行管理,包括event優先級等
- 至此就可以在event_base_new,event_new,event_add基礎上進行擴展,包括封裝socket api,設計tcp緩沖區等
源碼閱讀心得
其實主要還是細節問題,拋開各種錯誤處理不管,libevent可以學習的內容非常多
對io多路復用函數的封裝,實現跨平臺
如何對各種io復用函數的接口實現統一,是對其封裝首先要考慮的問題。為了統一,就需要設計一個統一的接口,在對io復用進行封裝時都根據這個統一接口進行。
libevent便是設計了統一的接口struct,內部包含io復用名字字符串,io函數的各種接口的函數指針。這樣在封裝時只需要每一個io復用函數都按照這種格式提供響應的字符串和函數指針,在base的調用中就不需要關系具體是哪個io函數了
此外對于每一個io復用函數使用的數據,比說說poll的pollfd,epoll的epoll_event,select的fd_set也需要統一的管理,但這個管理就不需要那么中規中矩了,因為這些數據是在每個io多路復用函數內部接口使用的,而這些內部接口如何使用數據在寫程序的時候就是知道的,比如說epoll知道如何使用epoll_event,select知道如何使用fd_set等。所以在設計時為了方便簡單的封裝以下就可以。
比較特別的是select對于fd_set的封裝,因為每次select之前都需要手動FD_ZERO,然后手動FD_SET所有fd,很麻煩,所以在對其封裝時對每個fd_set都有一份拷貝,添加刪除fd時用一個,select時將這個fd_set拷貝到另一個,使用拷貝后的調用select
對于跨平臺,其實就是把所有平臺能夠使用的io函數都羅列出來,根據預編譯頭進行篩選
可以參考io多路復用的封裝和使用
將信號統一到event上
信號發生和描述符可讀可寫沒有半點關系,想要把它們扯上關系,libevent的做法還是很值得學習的
具體可以參考統一事件源
數據結構的實現
libevent內部實現了hashmap,max-heap,queue,這些可以參考STL的源碼實現
tcp緩沖區的設計
內核提供的tcp緩沖區某種程度上已經可以滿足需求了,但是當寫入一個已經滿的內核tcp緩沖區時,io函數會出現阻塞,如果非阻塞io則會出現錯誤,極大增加了不穩定性。
其實設計緩沖區的目的就在于把所有的io函數的讀寫的數據都經由自己設計的緩沖區轉發。比如說,使用send寫入數據,會直接寫到程序緩沖區,待tcp內核緩沖區處于可寫,由程序自動寫入。而用戶不會知道在這個過程中其實經過了一個程序緩沖區
需要學習的就是緩沖區如何增加刪除以及數據如何讀出和寫入,對于緩沖區的動態變化,libevent做的還是很好的。一個鏈表連接著一個個內存塊,每次寫入數據都找最后一個有數據的內存塊后面的內存塊,讀數據尋找第一個有數據的內存塊,然后對內存塊進行調整
總結
以上是生活随笔為你收集整理的libevent源码学习-----阅读心得的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux网络编程-----非阻塞con
- 下一篇: libevent源码学习----io多路