Linux IO多路複用模型 : select epoll

前言

爲什麼要使用IO多路轉接模型?
試想一下,如果A想接收B的消息,那麼A就需要創建一個進程(或線程),用while(1)循環一直監視B是否給A發來消息,同時B也一直需要監視A,這會讓系統的開銷變得很大。
IO多路轉接模型的函數select, 可以幫助我們同時監視多個文件句柄, 這樣極大地降低了 內存 與 CPU 的開銷。

select

  • int select(int maxFd, fdset* rdset, fdset* wrset, fdset* exceptionset, struct timeval*)
    select函數的本質:將加入的文件句柄進行監視, 如果讀集合有可讀的情況 或者 寫集合有可寫的情況,那麼將向下執行
    出錯時返回 -1
    超時返回 0
    正常情況下返回一個 大於0 的數

參數說明
maxfd: 文件句柄的最大值+1,如0, 1, 2分別代表輸入,輸出,錯誤輸出,那麼maxfd應該是現有的fd的最大值+1, select的本質是循環

rdset: 讀文件句柄的集合,當檢測的文件句柄中有可讀的情況時,開始往下執行

wrset: 寫文件句柄的集合,當檢測的文件句柄中有可寫的情況時,開始往下執行,一般來說文件句柄均爲可寫的情況

exceptionset: 異常文件句柄的集合

struct timeval:等待時間 NULL表示select函數阻塞並無限等待,0表示select函數非阻塞不等待,傳入timeval則表示阻塞等待的時間

文件句柄的函數:

  • FD_ZERO(fd_set* sets)
    清空sets集合中原來的文件句柄
  • FD_SET(int fd, fd_set* sets)
    添加文件句柄到集合中
  • FD_ISSET(int fd, fd_set* sets)
    判斷文件句柄在sets集合中是否有設定

epoll

epoll相比於select有三個優點

  1. select在每一次循環的時候都需要重新設置需要監聽的句柄,epoll則不必
  2. select對每一個需要監聽的句柄都要遍歷詢問,epoll則是直接將準備就緒的句柄加入就緒隊列,並返回就緒句柄數量
  3. epoll的最大連接數可以設置得非常的大,而select則只能設置很少

select相當於O(N)的時間複雜度,當有句柄準備就緒時,它並不知道是哪一個準備就緒,只能進行輪詢;
epoll相當於O(1)的時間複雜度,它會精準的知道是哪些句柄準備就緒,並返回就緒句柄的數量。
在有大量的併發連接,且真正需要數據交換的有效連接較少的情況下,epoll的效率則比select大了許多。

  • int epoll_create(int __size)

size目前這個參數已經不被需要,我們通常將它設置爲1.
成功則返回一個epoll句柄,失敗返回-1

  • int epoll_ctl(int __epfd, int __op, int __fd, epoll_event * event)

epfd:epoll句柄
op: 需要進行的操作,有 EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL
fd : 需要進行操作的句柄
event : 一個結構體, 用於與op結合進行操作

  • int epoll_wait(int __epfd, epoll_event *__events, int __maxevents, int __timeout)

epfd: epoll句柄
events: 傳入event數組,將準備就緒的句柄賦值到event數組中
maxevents: event數組的容量
timeout: 超時機制,-1則是永久等待,0則是不等待,正數則是等待毫秒
返回值:成功則返回的是準備就緒的句柄數量,也就是event數組被賦值的數量,失敗返回-1, 超時返回0
epoll_wait在函數的形式上接近select


實戰項目

一個基於epoll 實現與 select 實現的聊天室項目:

Linux實戰項目 聊天室

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章