IO多路轉接

1.select

初識select

系統提供 select 函數來實現多路復用輸入 / 輸出模型 .
select 系統調用是用來讓我們的程序監視多個文件描述符的狀態變化的 ;
程序會停在 select 這里等待,直到被監視的文件描述符有一個或多個發生了狀態改變 ;

select函數模型

select的函數原型如下: #include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
??????????????????fd_set *exceptfds, struct timeval *timeout);

參數解釋

參數 nfds 是需要監視的最大的文件描述符值 +1
rdset,wrset,exset 分別對應于需要檢測的可讀文件描述符的集合,可寫文件描述符的集 合及異常文件描述符的集合;
參數 timeout 為結構 timeval ,用來設置 select() 的等待時間

參數timeout取值

NULL :則表示 select ()沒有 timeout select 將一直被阻塞,直到某個文件描述符上發生了事件 ;
0 :僅檢測描述符集合的狀態,然后立即返回,并不等待外部事件的發生。
特定的時間值:如果在指定的時間段里沒有事件發生, select 將超時返回。

關于fd_set結構

其實這個結構就是一個整數數組 , 更嚴格的說 , 是一個 " 位圖 ". 使用位圖中對應的位來表示要監視的文件描述符 .
提供了一組操作 fd_set 的接口 , 來比較方便的操作位圖 .

void FD_CLR(int fd, fd_set *set); // 用來清除描述詞組 set 中相關 fd 的位
int FD_ISSET(int fd, fd_set *set); // 用來測試描述詞組 set 中相關 fd 的位是否為真
void FD_SET(int fd, fd_set *set); // 用來設置描述詞組 set 中相關 fd 的位
void FD_ZERO(fd_set *set); // 用來清除描述詞組 set 的全部位

timeval結構

timeval 結構用于描述一段時間長度,如果在這個時間內,需要監視的描述符沒有事件發生則函數返回,返回值為0。

函數返回值

執行成功則返回文件描述詞狀態已改變的個數
如果返回 0 代表在描述詞狀態改變前已超過 timeout 時間,沒有返回
當有錯誤發生時則返回 -1 ,錯誤原因存于 errno ,此時參數 readfds writefds, exceptfds timeout 的值變成不可預測。
錯誤值可能為:
EBADF 文件描述詞為無效的或該文件已關閉
EINTR 此調用被信號所中斷
EINVAL 參數 n 為負值。
ENOMEM 核心內存不足

select執行流程

理解 select 模型的關鍵在于理解 fd_set, 為說明方便,取 fd_set 長度為 1 字節, fd_set 中的每一 bit 可以對應一個文件描述符fd 。則 1 字節長的 fd_set 最大可以對應 8 fd
* 1 )執行 fd_set set; FD_ZERO(&set); set 用位表示是 0000,0000 * 2 )若 fd 5, 執行 FD_SET(fd,&set); 后set 變為 0001,0000( 5 位置為 1) * 3 )若再加入 fd 2 fd=1, set 變為 0001,0011 * 4 )執行select(6,&set,0,0,0)阻塞等待 * 5 )若 fd=1,fd=2 上都發生可讀事件,則 select 返回,此時 set 變為0000,0011。注意:沒有事件發生的 fd=5 被清空

select就緒條件

讀就緒

socket 內核中 , 接收緩沖區中的字節數 , 大于等于低水位標記 SO_RCVLOWAT. 此時可以無阻塞的讀該文件描述符, 并且返回值大于 0;
socket TCP 通信中 , 對端關閉連接 , 此時對該 socket , 則返回 0;
監聽的 socket 上有新的連接請求 ;
socket 上有未處理的錯誤 ;

寫就緒

socket 內核中 , 發送緩沖區中的可用字節數 ( 發送緩沖區的空閑位置大小 ), 大于等于低水位標記SO_SNDLOWAT, 此時可以無阻塞的寫 , 并且返回值大于 0;
socket 的寫操作被關閉 (close 或者 shutdown). 對一個寫操作被關閉的 socket 進行寫操作 , 會觸發 SIGPIPE信號;
socket 使用非阻塞 connect 連接成功或失敗之后 ;
socket 上有未讀取的錯誤 ;

異常就緒

socket 上收到帶外數據 . 關于帶外數據 , TCP 緊急模式相關 ( 回憶 TCP 協議頭中 , 有一個緊急指針的字段 )

select的特點

可監控的文件描述符個數取決與 sizeof(fd_set) 的值 . 我這邊服務器上 sizeof(fd_set) 512 ,每 bit 表示一個文件描述符,則我服務器上支持的最大文件描述符是512*8=4096.
fd 加入 select 監控集的同時,還要再使用一個數據結構 array 保存放到 select 監控集中的 fd
一是用于再 select 返回后, array 作為源數據和 fd_set 進行 FD_ISSET 判斷。
二是 select 返回后會把以前加入的但并無事件發生的 fd 清空,則每次開始 select 前都要重新從 array 取得fd逐一加入 (FD_ZERO 最先 ) ,掃描 array 的同時取得 fd 最大值 maxfd ,用于 select 的第一個參數。

select的優點

1.可移植性好:select幾乎在所有的平臺上都支持,具有良好的跨平臺兼容性。

2.超時精度高:select對于超時值的精度可以達到微秒級別,比poll的毫秒級別精度更高。

select的缺點

1.每次調用 select, 都需要手動設置 fd 集合 , 從接口使用角度來說也非常不便 .
2.每次調用 select ,都需要把 fd 集合從用戶態拷貝到內核態,這個開銷在 fd 很多時會很大
3.同時每次調用 select 都需要在內核遍歷傳遞進來的所有 fd ,這個開銷在 fd 很多時也很大
4.select 支持的文件描述符數量太小
5.代碼編寫難度大

?select的一般編碼格式

1.需要有一個第三方數組,用來保存所以合法的fd

2.while(true)

{

? ? ? ? 1.遍歷數組,更新出最大值

? ? ? ? 2.遍歷數組,添加所有需要關心的fd到fd_set位圖中

? ? ? ? 3.調用select進行事件檢測

? ? ? ? 4.遍歷數組,找到就緒的事件,根據就緒事件,完成對應的動作

}

2.poll

poll函數接口

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// pollfd 結構
struct pollfd {
????????int fd; /* file descriptor */
????????short events; /* requested events */
????????short revents; /* returned events */
};

參數說明

fds 是一個 poll 函數監聽的結構列表 . 每一個元素中 , 包含了三部分內容 : 文件描述符 , 監聽的事件集合 , 返回的事件集合.
nfds 表示 fds 數組的長度 .
timeout 表示 poll 函數的超時時間 , 單位是毫秒 (ms)?

events和revents的取值

返回結果

返回值小于 0, 表示出錯 ;
返回值等于 0, 表示 poll 函數等待超時 ;
返回值大于 0, 表示 poll 由于監聽的文件描述符就緒而返回 .

poll的優點

1.效率高
2.輸入輸出參數分離,不需要進行大量的重置
3.poll參數級別,沒有可以管理的fd上限

poll的缺點

1.poll依舊需要不少的遍歷,在用戶層檢測事件就緒與內核檢測fd就緒,都是一樣的,用戶還需要維護數組

2.poll需要內核到用戶的拷貝

3.poll的代碼也比較復雜?

3.epoll

按照man手冊的說法: 是為處理大批量句柄而作了改進的poll.

epoll 3 個相關的系統調用 .
1.epoll_create

?int epoll_create(int size);

2.epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

它不同于 select() 是在監聽事件時告訴內核要監聽什么類型的事件 , 而是在這里先注冊要監聽的事件類型 .
第一個參數是 epoll_create() 的返回值 (epoll 的句柄 ).
第二個參數表示動作,用三個宏來表示 .
第三個參數是需要監聽的 fd.
第四個參數是告訴內核需要監聽什么事

第二個參數的取值

EPOLL_CTL_ADD :注冊新的 fd epfd 中;
EPOLL_CTL_MOD :修改已經注冊的 fd 的監聽事件;
EPOLL_CTL_DEL :從 epfd 中刪除一個 fd

struct epoll_event結構如下:

events 可以是以下幾個宏的集合:
EPOLLIN : 表示對應的文件描述符可以讀 ( 包括對端 SOCKET 正常關閉 );
EPOLLOUT : 表示對應的文件描述符可以寫 ;
EPOLLPRI : 表示對應的文件描述符有緊急的數據可讀 ( 這里應該表示有帶外數據到來 );
EPOLLERR : 表示對應的文件描述符發生錯誤 ;
EPOLLHUP : 表示對應的文件描述符被掛斷 ;
EPOLLET : EPOLL 設為邊緣觸發 (Edge Triggered) 模式 , 這是相對于水平觸發 (Level Triggered) 來說的 .
EPOLLONESHOT :只監聽一次事件 , 當監聽完這次事件之后 , 如果還需要繼續監聽這個 socket 的話 , 需要再次把這個socket 加入到 EPOLL 隊列里 .

3.epoll_wait

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);?

收集在 epoll 監控的事件中已經發送的事件 .
參數 events 是分配好的 epoll_event 結構體數組 .
epoll 將會把發生的事件賦值到 events 數組中 (events 不可以是空指針,內核只負責把數據復制到這個events數組中,不會去幫助我們在用戶態中分配內存 ).
maxevents 告之內核這個 events 有多大,這個 maxevents 的值不能大于創建 epoll_create() 時的 size.
參數 timeout 是超時時間 ( 毫秒, 0 會立即返回, -1 是永久阻塞 ).
如果函數調用成功,返回對應 I/O 上已準備好的文件描述符數目,如返回 0 表示已超時 , 返回小于 0 表示函數失敗.

epoll的工作原理?

首先,epoll區別于select和poll的點在于,就緒是通過下層主動來的。

?

epoll模型:?

當某一進程調用 epoll_create 方法時, Linux 內核會創建一個 eventpoll 結構體,這個結構體中有兩個成員與epoll 的使用方式密切相關。
每一個 epoll 對象都有一個獨立的 eventpoll 結構體,用于存放通過 epoll_ctl 方法向 epoll 對象中添加進來的事件.
這些事件都會掛載在紅黑樹中,如此,重復添加的事件就可以通過紅黑樹而高效的識別出來 ( 紅黑樹的插入時間效率是lgn ,其中 n 為樹的高度 ).
而所有添加到 epoll 中的事件都會與設備 ( 網卡 ) 驅動程序建立回調關系,也就是說,當響應的事件發生時會調用這個回調方法.
這個回調方法在內核中叫 ep_poll_callback, 它會將發生的事件添加到 rdlist 雙鏈表中 .
epoll 中,對于每一個事件,都會建立一個 epitem 結構體 .
struct eventpoll{
....
/* 紅黑樹的根節點,這顆樹中存儲著所有添加到 epoll 中的需要監控的事件 */
struct rb_root rbr;
/* 雙鏈表中則存放著將要通過 epoll_wait 返回給用戶的滿足條件的事件 */
struct list_head rdlist;
....
};

struct epitem{
struct rb_node rbn;// 紅黑樹節點
struct list_head rdllink;// 雙向鏈表節點
struct epoll_filefd ffd; // 事件句柄信息
struct eventpoll *ep; // 指向其所屬的 eventpoll 對象
struct epoll_event event; // 期待發生的事件類型
}
當調用 epoll_wait 檢查是否有事件發生時,只需要檢查 eventpoll 對象中的 rdlist 雙鏈表中是否有 epitem元素即可.
如果 rdlist 不為空,則把發生的事件復制到用戶態,同時將事件數量返回給用戶 . 這個操作的時間復雜度
O(1).

epoll的優點

1.接口使用方便 : 雖然拆分成了三個函數 , 但是反而使用起來更方便高效 . 不需要每次循環都設置關注的文件描述符, 也做到了輸入輸出參數分離開
2.數據拷貝輕量 : 只在合適的時候調用 EPOLL_CTL_ADD 將文件描述符結構拷貝到內核中 , 這個操作并不頻繁( select/poll 都是每次循環都要進行拷貝 )
3.事件回調機制 : 避免使用遍歷 , 而是使用回調函數的方式 , 將就緒的文件描述符結構加入到就緒隊列中 ,epoll_wait 返回直接訪問就緒隊列就知道哪些文件描述符就緒 . 這個操作時間復雜度 O(1). 即使文件描述符數目很多, 效率也不會受到影響 .
4.沒有數量限制 : 文件描述符數目無上限

epoll工作方式

epoll2種工作方式-水平觸發(LT)和邊緣觸發(ET).

水平觸發 Level Triggered 工作模式
epoll 默認狀態下就是 LT 工作模式 .
epoll 檢測到 socket 上事件就緒的時候 , 可以不立刻進行處理 . 或者只處理一部分 .
如上面的例子 , 由于只讀了 1K 數據 , 緩沖區中還剩 1K 數據 , 在第二次調用 epoll_wait , epoll_wait 仍然會立刻返回并通知socket 讀事件就緒 .
直到緩沖區上所有的數據都被處理完 , epoll_wait 才不會立刻返回 .
支持阻塞讀寫和非阻塞讀寫
邊緣觸發 Edge Triggered 工作模式
如果我們在第 1 步將 socket 添加到 epoll 描述符的時候使用了 EPOLLET 標志 , epoll 進入 ET 工作模式 .
epoll 檢測到 socket 上事件就緒時 , 必須立刻處理 .
如上面的例子 , 雖然只讀了 1K 的數據 , 緩沖區還剩 1K 的數據 , 在第二次調用 epoll_wait 的時候 ,
epoll_wait 不會再返回了 .
也就是說 , ET 模式下 , 文件描述符上的事件就緒后 , 只有一次處理機會 .
ET 的性能比 LT 性能更高 ( epoll_wait 返回的次數少了很多 ). Nginx 默認采用 ET 模式使用 epoll.
只支持非阻塞的讀寫

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715066.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715066.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715066.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

服務器硬件得基礎知識介紹

服務器硬件是計算機硬件的一種&#xff0c;專門用于構建服務器系統。服務器硬件通常具有高性能、高可靠性和可擴展性等特點&#xff0c;以滿足企業級應用的需求。本文將從以下幾個方面介紹服務器硬件的基礎知識&#xff1a;服務器概述、CPU、內存、存儲、網絡、電源和散熱、服務…

【機器學習】CIFAR-10數據集簡介、下載方法(自動)

【機器學習】CIFAR-10數據集簡介、下載方法(自動) &#x1f308; 個人主頁&#xff1a;高斯小哥 &#x1f525; 高質量專欄&#xff1a;Matplotlib之旅&#xff1a;零基礎精通數據可視化、Python基礎【高質量合集】、PyTorch零基礎入門教程&#x1f448; 希望得到您的訂閱和支…

0904多元復合函數求導-多元函數微分法及其應用

文章目錄 1 復習一元函數復合函數求導2 一元函數與多元函數復合的情形3 多元函數與多元函數復合的情形4 其他情形5 抽象復合函數求導6 全微分不變性結語 1 復習一元函數復合函數求導 y f ( u ) , u ? ( x ) ? f [ ? ( x ) ] d y d x d y d u ? d u d x f ′ ( u ) ? ?…

Python正則表達式:從基礎到高級應用的全面總結與實戰【第103篇—JSON模塊】

Python正則表達式&#xff1a;從基礎到高級應用的全面總結與實戰 正則表達式是一種強大的文本匹配和處理工具&#xff0c;廣泛應用于文本處理、數據抽取、表單驗證等領域。本文將從正則表達式的基礎知識出發&#xff0c;逐步深入&#xff0c;最終結合代碼實戰&#xff0c;帶你…

趙文彬將出席無磷鍋爐工藝助劑在鍋爐水節水節能應用

演講嘉賓&#xff1a;趙文彬 集團副總/技術總監 上遠未來水務集團有限公司 演講題目&#xff1a;無磷鍋爐工藝助劑在鍋爐水節水節能方面的應用 會議簡介 “十四五”規劃中提出&#xff0c;提高工業、能源領城智能化與信息化融合&#xff0c;明確“低碳經濟”新的戰略目標&a…

mac 安裝hbuilderx

下載 HBuilderX下載地址: 下載地址 選額mac版本點擊下載 安裝 如圖&#xff0c;將HBuilderX拖到Applications&#xff0c;才是正確的安裝姿勢。 MacOSX&#xff0c;軟件必須安裝到/Applications目錄&#xff0c;如未安裝到此目錄&#xff0c;可能會出現插件安裝失敗、項目創建…

基于BERTopic模型的中文文本主題聚類及可視化

文章目錄 BERTopic簡介模型加載地址文本加載數據處理BERTopic模型構建模型結果展示主題可視化總結BERTopic簡介 BERTopic論文地址:BERTopic: Neural topic modeling with a class-based TF-IDF procedure BERTopic是一種結合了預訓練模型BERT和主題建模的強大工具。它允許我…

Linux中的動靜態庫

目錄 一、靜態庫 &#xff08;1&#xff09;靜態庫的優缺點&#xff1a; &#xff08;2&#xff09;Linux下靜態庫的創建和執行 1.直接編譯?編輯 2.指定路徑和庫名 3.用LIBRARY_PATH環境變量來配置路徑 二、動態庫 &#xff08;1&#xff09;動態庫的優缺點 &#xff…

javaweb請求與響應

前言 前面介紹了對應的服務器端的相關代碼。這里開始學習服務器端與客戶端的數據請求與響應 這里的僅僅是一個簡單的調用&#xff0c;并沒有經過servelert接口來進行調用&#xff0c;同前面的一樣&#xff0c;我們介紹對應的本地服務器進行的部署項目。 代碼 //屬于簡單的不…

Java學習—線程的創建

Java 中的多線程是一種強大的機制&#xff0c;允許程序同時執行兩個或兩個以上的部分。這些同時執行的部分被稱為線程&#xff0c;它們可以使程序的執行更加高效&#xff0c;特別是在進行大量計算或等待資源&#xff08;比如網絡資源或文件系統&#xff09;時。Java 提供了在程…

Scratch 第十三課-飛機大戰游戲

第十三課-飛機大戰游戲 學習目標 這節課我們做一款大家都愛玩的飛機大戰游戲&#xff0c;學習重點&#xff1a; 如何導入外部角色如何讓飛機發射子彈鼠標控制角色移動 程序設計 程序分析 &#xff1a; 飛機大戰游戲相信很多小朋友都玩過&#xff0c;我方飛機在下方&#xf…

LabVIEW石油鉆機提升系統數字孿生技術

LabVIEW石油鉆機提升系統數字孿生技術 隨著數字化、信息化、智能化的發展&#xff0c;石油鉆采過程中的石油鉆機數字化技術提升成為了提高鉆井效率、降低生產成本的重要途徑。基于中石油云平臺提供的數據&#xff0c;采用數字孿生技術&#xff0c;對石油鉆機提升系統進行數字化…

[Redis]——初識Redis

一、Redis為非關系型數據庫 ?我們常見的MySQL、SQLServer都是關系型數據庫&#xff0c;那他們之間有什么區別與聯系呢&#xff1f; &#x1f4d5;關系型數據庫與非關系型數據庫的區別&#xff08;面試題&#xff09; 解釋&#xff1a; SQL數據庫中的表是有結構的&#xff0c;包…

騰訊云學生云服務器_學生云主機_學生云數據庫_云+校園特惠套餐

2024年騰訊云學生服務器優惠活動「云校園」&#xff0c;學生服務器優惠價格&#xff1a;輕量應用服務器2核2G學生價30元3個月、58元6個月、112元一年&#xff0c;輕量應用服務器4核8G配置191.1元3個月、352.8元6個月、646.8元一年&#xff0c;CVM云服務器2核4G配置842.4元一年&…

小程序和頁面生命周期詳解

目錄 小程序的生命周期 創建&#xff08;onLoad&#xff09;&#xff1a; 顯示&#xff08;onShow&#xff09;&#xff1a; 隱藏&#xff08;onHide&#xff09;&#xff1a; 卸載&#xff08;onUnload&#xff09;&#xff1a; 錯誤監聽&#xff08;onError&#xff09;…

JVM 第二部分-2(堆,方法區)

4.堆 堆 一個Java程序&#xff08;main方法&#xff09;對應一個jvm實例&#xff0c;一個jvm實例只有一個堆空間堆是jvm啟動的時候就被創建&#xff0c;大小也確定了。大小可以用參數設置。堆是jvm管理的一塊最大的內存空間 核心區域&#xff0c;是垃圾回收的重點區域堆可以位…

洛谷P1509找啊找啊找GF

題解&#xff1a;這題我們需要考慮兩個因素 &#xff0c;既要有錢&#xff0c;也需要有人品&#xff0c;但是呢&#xff0c;還想花最少得時間泡到最多的女生&#xff0c;那么這題我們就要用到以往的二維dp數組&#xff0c;但是真的是二維的嗎&#xff1f;不&#xff0c;因為要考…

如何讓大項目自動化測試更加靈活簡潔

如何把大象放到冰箱里&#xff1f;第一打開冰箱門&#xff0c;第二把大象放進去&#xff0c;第三把冰箱門關好。 這個問題言外之意是大象那么大&#xff0c;怎么能放進冰箱&#xff0c;為什么要把大象放冰箱&#xff0c;就開始糾結這個問題了&#xff0c;它是想表明不用太多糾結…

Day20-磁盤管理

Day20-磁盤管理 1. cut 切:2. 磁盤歷史和內外部物理結構介紹2.1 磁盤發展趨勢和實現措施2.2 磁盤知識的體系結構2.3 機械磁盤的外部結構2.4 SSD固態硬盤的外部結構2.5 固態硬盤內部結構2.6 緩存在服務器各硬件上的速度和大小對比另類維度圖解&#xff0c;從上到下由高速到低速&…

DataX及Datax-web雜記

&#x1f47d;個人博客&#xff1a;https://everspring.github.io/ &#x1f47d;公眾號&#xff1a;愛歷史的IT男 一. DataX調試 DataX之前調試不是很方便&#xff0c;要打包后才能調試。23年7月后一位叫"FuYouJ "的開源者提交了datax-example模塊&#xff0c;就方…