I/O複用模型
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL5FkeOd3a65UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2kjM4ATM0UTM0ETOwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
一、select 函數
select能監聽的檔案描述符受限于FD_SETSIZE,一般為1024,單純的改變程序打開的檔案描述符個數并不能改變select監聽檔案個數;解決1024以下用戶端時使用select是很适合的,但如果連結用戶端過多,select采用的是輪詢模型,會大大降低伺服器響應效率,不應在使用select。
nfds:監控的檔案描述符裡最大檔案描述符加1,此參數會告訴核心檢測前多少個檔案描述符的狀态
readfds:監控有讀資料到達檔案描述符集合,傳入傳出參數
writefds:監控寫資料到達檔案描述符集合,傳入傳出參數
exceptfds:監控異常到達檔案描述符集合,帶外資料到達異常,傳入傳出參數
timeout:定時阻塞監控時間,3種情況:
①:NULL,永遠等下去
②:設定timeval,等待固定時間
③:設定timeval裡時間均為0,檢查描數字後立即傳回,輪詢
伺服器端代碼已經實作了 但是用傻瓜指令nc去ping伺服器時 結果還正确,代碼放檔案夾裡
二、poll函數
與select函數類似,不過沒有監管檔案描述符個數的限制。
①fds:指向一個結構體數組的第個元素指針,每個數組元素都是一個struct pollfd結構,用于指定測試給某個給定的fd的條件
②nfds:表示fds結構體數組的長度
③timeout:表示poll函數的逾時時間,機關是毫秒
與select不一樣,poll函數中第一個參數引入了pollfd 這個結構體的數組,數組中的每一個元素表示了要監管的套接字,這個結構體如下:
通過給pollfd 結構的fd成員指派,同時設定好events參數,表示就把這個檔案描述符加到poll函數的監管清單去了。Poll函數中的events參數,在指定單個檔案描述符的時候就指定要監管的事件。
三、epoll函數
epoll使用過程分為3步:
①調用epoll_create建立一個epoll句柄(epoll對象);
②調用epoll_ctl函數對需要監控的檔案描述符進行增删改;
③調用epoll_wait函數等待檔案描述符就緒。
1.epoll_create():調用epoll_create函數,成功之後會傳回一個檔案描述符,這個檔案描述符也就是建立出來的epoll對象,是以當用完之後需要調用close函數來關閉這個檔案描述符,否則會導緻檔案描述符用盡。
①eoll_create函數調用epoll_create1函數,epoll_create1函數裡面調用ep_alloc函數,ep_alloc函數會調用相關的函數初始化epoll對象的就緒隊列(一個空的就緒隊列,當某個檔案描述符指定的事件發生時,就會将該檔案描述符相應的資訊放在該就緒隊列中);
②ep_alloc函數還會調用相關函數初始化紅黑樹;
③epoll_create1函數還會調用 anon_inode_getfd()函數,該函數會配置設定一個空閑描述符,會建立一個匿名檔案,将該空閑檔案描述符與匿名檔案相關聯,該空閑檔案描述符就是調用epoll_create函數成功後的傳回值(也就是epoll對象);
2.epoll_ctl:對epoll對象epfd,對于檔案描述符fd執行什麼樣的操作,可以将fd注冊進epfd中,也可以删除epfd中的fd,還可以修改fd監聽的事件。
epfd:是epoll_create函數建立的epoll對象
op:對該epfd的相關操作(三個取值:EPOLL_CTL_ADD;EPOLL_CTL_DEL;EPOLL_CTL_MOD)
fd:需要監聽的檔案描述符
event:是一個結構體的位址,該結構體用來告訴核心需要監聽的事件是什麼,需要監聽的資料是什麼類型的。
3.epoll_wait:收集在epfd中已經就緒的事件
events:這裡的events是一個struct epoll_event的數組,該數組裡面存放核心拷貝至使用者空間中已經就緒的檔案描述符相關資訊,該數組的每個元素都是一個epoll_event的結構體
maxevents:表示events數組的大小
timeout:表示逾時時間,以毫秒為機關,如果為0則不會阻塞立即傳回,-1是永久阻塞
函數執行的操作:
①當使用者調用epoll_wait函數時,使用者需要自己傳入一個epoll_event數組,以及該數組的大小,還會傳入一個逾時時間;
②epoll_wait函數首先會檢查使用者傳入的參數是否合法(events數組是否可寫,maxevents是否為有效大小);
③epoll_wait主要調用ep_poll函數擷取事件,ep_poll函數會檢查就緒隊列是否為空,如果就緒隊列為空,就将該程序加入到eventpoll的等待隊列中,等待被回調函數喚醒或者到了逾時時間,如果過了逾時時間還沒有被喚醒,epoll_wait函數也會傳回,傳回0,如果就緒隊列不為空,就将就緒隊列裡面的事件拷貝至使用者傳入的events數組中,并且将就緒檔案描述符的數量傳回給使用者。
④因為一次不會有多個檔案描述符相應的事件就緒,也就是就緒隊列不會很長,則核心将就緒隊列中的内容拷貝至使用者空間的時間複雜度接近于O(1),這也是epoll高效的展現。
⑤epoll_wait函數成功傳回的是就緒的檔案描述符的個數,也就是events數組裡面有效内容的大小,通過周遊events數組,就可以得到相應的檔案描述符和事件,根據不同的檔案描述符就可以采取不同的操作。