進程級的描述符表的每壹條目記錄了單個文件描述符的相關信息。
1. 控制文件描述符操作的壹組標誌。(目前,此類標誌僅定義了壹個,即close-on-exec標誌)
2. 對打開文件句柄的引用
內核對所有打開的文件的文件維護有壹個系統級的描述符表格(open file description table)。有時,也稱之為打開文件表(open file table),並將表格中各條目稱為打開文件句柄(open file handle)。壹個打開文件句柄存儲了與壹個打開文件相關的全部信息,如下所示:
1. 當前文件偏移量(調用read()和write()時更新,或使用lseek()直接修改)
2. 打開文件時所使用的狀態標識(即,open()的flags參數)
3. 文件訪問模式(如調用open()時所設置的只讀模式、只寫模式或讀寫模式)
4. 與信號驅動相關的設置
5. 對該文件i-node對象的引用
6. 文件類型(例如:常規文件、套接字或FIFO)和訪問權限
7. 壹個指針,指向該文件所持有的鎖列表
8. 文件的各種屬性,包括文件大小以及與不同類型操作相關的時間戳
下圖展示了文件描述符、打開的文件句柄以及i-node之間的關系,圖中,兩個進程擁有諸多打開的文件描述符。
Epoll - I/O event notification facility
翻譯壹下,epoll是壹種I/O事件通知機制,這句話基本上包含了所有需要理解的要點:
epoll是壹種當文件描述符的內核緩沖區非空的時候,發出可讀信號進行通知,當寫緩沖區不滿的時候,發出可寫信號通知的機制
epoll的接口非常簡單,壹***就三個函數:
events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽壹次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裏
首先通過 create_epoll(int maxfds) 來創建壹個epoll的句柄,其中 maxfds 為妳epoll所支持的最大句柄數。這個函數會返回壹個新的epoll句柄,之後的所有操作將通過這個句柄來進行操作。在用完之後,記得用 close() 來關閉這個創建出來的epoll句柄。
之後在妳的網絡主循環裏面,每壹幀的調用 epoll_wait(int epfd, epoll_event events, int max events, int timeout) 來查詢所有的網絡接口,看哪壹個可以讀,哪壹個可以寫了。基本的語法為:
nfds = epoll_wait(kdpfd, events, maxevents, -1);
其中kdpfd為用 epoll_create 創建之後的句柄,events是壹個 epoll_event* 的指針,當 epoll_wait 這個函數操作成功之後, epoll_events 裏面將儲存所有的讀寫事件。 max_events 是當前需要監聽的所有 socket 句柄數。 最後壹個 timeout 是 epoll_wait 的超時,為0的時候表示馬上返回,為-1的時候表示壹直等下去,直到有事件範圍,為任意正整數的時候表示等這麽長的時間,如果壹直沒有事件,則範圍。 壹般如果網絡主循環是單獨的線程的話,可以用-1來等,這樣可以保證壹些效率,如果是和主邏輯在同壹個線程的話,則可以用0來保證主循環的效率。
epoll_wait範圍之後應該是壹個循環,遍利所有的事件。
幾乎所有的epoll程序都使用下面的框架:
下面給出壹個完整的服務器端例子: