select,poll和epoll的API複習筆記

2021-10-10 18:36:35 字數 3375 閱讀 4816

環境:centos7 xshell

前言:select poll epoll 的區別一定要清楚

select 優點是跨平台,而poll相對其沒有1024檔案描述符的限制,

共有的缺點是:

1.每次監聽都需要將監聽的資訊從應用層拷貝到核心。

2.返回變化的檔案描述符的個數,具體哪個檔案描述符變化需要遍歷。

3.大量併發,少量活躍效率低。

解決此方案就是使用 epoll 比如阿里的伺服器就是 epoll+執行緒池

epoll優點:

1.沒有1024檔案描述符限制

2.下次監聽不需要將需要監聽的檔案描述符從應用層再次拷貝到核心

3.返回的是已經變化的檔案描述符,不需要遍歷

4.大量併發,少量活躍效率高

本文主要介紹的是其api的簡單運用

主程序通過多路io轉接技術 epoll 去監聽緩衝區,監聽第乙個沒有1024個檔案描述符的限制,第二個是給乙個陣列,每個成員是乙個結構體,包含:fd檔案描述符,event 讀事件,revent(返回監聽到什麼事件),如果監聽是讀事件則賦值返回,然後對於我們而言會對陣列每個成員進行遍歷,如果 event與revent相同即代表是讀事件,這裡和select其實沒區別,從應用層拷貝到核心層,那麼他好在**呢?原保留的名單不需要每次給?這裡是和select的乙個區別,然後就看 poll 的api

//man poll  了解一下此api

#include int poll(struct pollfd *fds, nfds_t nfds, int timeout);

/*功能:監聽多個檔案描述符的屬性變化,

引數: (我們在檢視引數型別的時候也要注意其是否是結構體)

nfds:監控陣列中有多少檔案描述符需要被監控 (陣列有效元素的最大下標+1)

timeout:毫秒級等待 (超時時間,填 -1 是永久監聽, >= 0 限時等待)

陣列元素 struct pllfd 是個結構體,

*/struct pollfd

;//poll 函式還是很簡單的

看了乙個poll的陣列實現的**

**講解:

對於struct pollfd結構體, fd 和 event 是請求引數,revent 是返回引數

比如對 client[0] 成員 fd = lfd event = pollin,監聽讀事件,而將其他成員的 fd 置於 -1,

if 判斷 client[0] 的 revent 返回的事件 與& 上pollin (為什麼不用==?位操作是為了安全,當監聽不止讀乙個變化時,此時的判斷用==就可能不相等,而只位操作識別讀事件絕對是成功的); accept 是 wrap檔案中的函式; 之後的for迴圈目的是找到乙個fd為-1,代表其是可用的元素; errno = econnreset 巨集代表等於它的時候 收到對方發的rst標誌,代表要斷開了; 和select陣列版基本相似, 這個**不是重點。

總結:poll的優缺點相對於 select

優點:沒有檔案描述符1024的限制,請求和返回是分離的

缺點:和select一樣,每次都需要將需要監聽的檔案描述符從應用層拷貝到核心,每次都需要將陣列中的元素遍歷一遍才知道哪個變化了。

大量併發,少量活躍效率低。

使用 epoll 的3個特點如下:

1.沒有檔案描述符的限制,可以擴充套件。

2.以後每次監聽都不用將需要監聽的檔案描述符拷貝到核心(或樹上)

3.返回的是已經變化的描述符,不需要遍歷樹。

(核心中有乙個核心鍊錶,比如誰變化了則放進此煉表中,然後將鍊錶拷貝到應用層,而對於應用層而言定義乙個陣列來接此鍊錶返回的引數即可,應用層只需要處理陣列就行了,這也是epoll相對於select和poll的優勢)

假設乙個程序, 使用epoll監聽,參考如下三步:

第一步要建立一棵紅黑樹,核心幫我們管理,我們呼叫介面去實現。

第二步上樹,將需要監聽的檔案描述符上樹。

第三步監聽。

(這裡是開啟終端使用man手冊查詢的,存在的多個api並未全拿出來,講常用api)

#include int epoll_create(int size);

引數size:監聽的檔案描述符的上限, 2.6版本之後寫1即可

當填的size如果不夠了,它會自動擴充套件,一般寫1必須大於0

返回值:返回樹的控制代碼 (用的時候當作檔案描述符用即可)

4個引數:

epfd:這是乙個控制代碼,通過這個控制代碼可以對樹下的檔案描述符進行操作,如何去維護我們不需要關心

fd:上樹下樹的檔案描述符 (檔案描述符可以作為檢驗書上節點是否存在 避免重複上下樹)

event:上樹的節點 (結構體) 其實是乙個結構體,看似很複雜 其實兩個引數

(epoll 是需要主動提供是何種事件,讀時間和寫事件分別為 epollin,epollout)

struct epoll_event

;typedef union epoll_data

epoll_data_t;

舉例:如何讓 cfd 上樹

int epfd = epoll_create(1); //1.建立1個紅黑樹,size自動擴充套件不用考慮

//第二步開始前需要預先設定幾個引數

struct epoll_event ev; //初始化結構體

ev.data.fd = cfd; //聯合體 fd 賦值

ev.events = epollin; //告知什麼事件

epoll_ctl(epfd,epoll_ctl_add,cfd, &ev); 2.上樹

//這裡已經上樹了為啥還多乙個檔案描述符 ? 是因為需要確認樹上是否已經存在此檔案描述符,避免重複

功能:監聽樹上檔案描述符的變化

四個引數

epfd: 樹的控制代碼,

maxevents: 陣列元素的個數

timeout: -1 代表永久監聽 大於等於0表示限時等待

返回值:返回的是變化的檔案描述符個數

select, poll和epoll的區別

我只用過select select 最不能忍受的是乙個程序所開啟的fd是有一定限制的,由fd setsize設定,預設值是2048。對於那些需要支援的上萬連線數目的im伺服器來說顯然太少了,select要掃瞄各個檔案描述符,而epool採用mmap更高效 select 系統呼叫提供乙個機制來實現同步...

select poll和epoll的區別

select,poll,epoll都是io多路復用的機制。i o多路復用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒 一般是讀就緒或者寫就緒 能夠通知程式進行相應的讀寫操作。select僅僅知道i o事件發生的檔案描述符的數量,但並不知道是哪幾個 1 時間複雜度 o n 2 優點 跨平台支...

select poll和epoll的區別

作業系統在處理io的時候,主要有兩個階段 我們一般將上述過程簡化理解為 select,poll,epoll都是io多路復用的機制。i o多路復用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒 一般是讀就緒或者寫就緒 能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都...