IO多路復用之select poll以及epoll

2021-07-10 13:33:43 字數 4515 閱讀 3315

處理執行態的程序(獲得cpu資源),由於需要等待一些事件的傳送而不能繼續執行時,就會祖東的轉為阻塞狀態,這是,他是不占用cpu資源的。因此也只有處於執行態的程序,才能夠轉為阻塞狀態。這時候排程器會切換到其他程序,一旦這個程序等待的事件發生了,那麼就會重新喚醒這個程序,重新等待被排程。一旦被排程器排程,那麼就會恢復到切換之前的狀態,繼續執行,由阻塞狀態切換到執行態。

乙個用於對檔案引用的抽象化概念。形式上就是乙個非負整數,乙個索引值,指向核心為每個程序維護的程序開啟檔案的記錄表。當程式開啟乙個現有檔案或者建立乙個新檔案的時候,核心就會向程序返回乙個檔案描述符。在linux中,將所有的外圍裝置也抽象為檔案,所以在驅動程式開發中,開啟乙個裝置,首先就需要獲得這個裝置對應的檔案描述符,然後持有這個描述符,就可以開啟並操作這個裝置了。

其實就是標準io,在linux中,當程序需要訪問檔案中資料時,會先將資料從磁碟檔案拷貝到核心的緩衝區,然後再從核心緩衝區拷貝到程序的位址空間中。這樣做的好處是實現了資料的共享,和保證資料在緩衝區中的時間盡可能的長。為什麼這麼說呢,因為從磁碟中讀取乙個檔案的速度和從記憶體中拷貝乙個資料的速度相差是100倍,一旦發生了一次資料的共享,那麼這麼一次周轉的開銷就是非常值得的。如果緩衝區中沒有,再從磁碟中去拷貝,這個過程進行了多次資料的拷貝操作,帶來的cpu和記憶體的開銷是非常大的。

當乙個read操作發生時,會經歷兩個階段:

1.資料從磁碟中拷貝到核心緩衝區

2.資料從核心緩衝區拷貝到程序位址空間。

正是由於這兩個階段,linux產生了下面五種網路模式的方案。

預設情況中所有的socket都是阻塞的,當使用者程序呼叫了recvfrom這個系統呼叫,然後kernel就會進入上述的兩個階段,這時候程序都是被阻塞的。當kernel一直等到資料準備好了,並拷貝到了使用者程序位址空間,然後kernel返回結果,使用者程序才會解除block的狀態,重新執行起來。

可以將socket設定為非阻塞的。當使用者程序發出read操作時,如果kernel中的資料還沒有準備好,那麼它並不會block使用者程序,而是立刻返回乙個error。從使用者程序角度講 ,它發起乙個read操作後,並不需要等待,而是馬上就得到了乙個結果。使用者程序判斷結果是乙個error時,它就知道資料還沒有準備好,於是它可以再次傳送read操作。一旦kernel中的資料準備好了,並且又再次收到了使用者程序的system call,那麼它馬上就將資料拷貝到了使用者記憶體,然後返回。

所以,特點就是使用者程序需要不斷的主動詢問kernel資料是否準備好。

io multiplexing就是我們說的select,poll,epoll,有些地方也稱這種io方式為event driven io。select/epoll的好處就在於單個process就可以同時處理多個網路連線的io。它的基本原理就是select,poll,epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有資料到達了,就通知使用者程序。

當使用者程序呼叫了select,那麼整個程序會被block,而同時,kernel會「監視」所有select負責的socket,當任何乙個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從kernel拷貝到使用者程序。

所以,i/o 多路復用的特點是通過一種機制乙個程序能同時等待多個檔案描述符,而這些檔案描述符(套接字描述符)其中的任意乙個進入讀就緒狀態,select()函式就可以返回。在io multiplexing model中,實際中,對於每乙個socket,一般都設定成為non-blocking,但是,如上圖所示,整個使用者的process其實是一直被block的。只不過process是被select這個函式block,而不是被socket io給block。

使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何block。然後,kernel會等待資料準備完成,然後將資料拷貝到使用者記憶體,當這一切都完成之後,kernel會給使用者程序傳送乙個signal,告訴它read操作完成了。

select,poll,epoll都是io多路復用的機制。i/o多路復用就是通過一種機制,乙個程序可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步i/o,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而非同步i/o則無需自己負責進行讀寫,非同步i/o的實現會負責把資料從核心拷貝到使用者空間。

select函式監視的檔案描述符有3類,writefd,readfd,exceptfd.呼叫select函式會阻塞,直到有描述符就緒,或者超時,函式會返回。返回之後,可以通過遍歷fdset,找出就緒的描述符,然後再呼叫recvfrom函式將資料從緩衝區拷貝到程序位址空間。

缺點在於單個程序能夠監測的檔案描述符的數量存在最大限制,linux上一般為1024。通過重新編譯核心或者修改巨集定義可以提公升這個限制,但是會造成效率的降低。

不同與select使用三個點陣圖來表示三個fdset的方式,poll使用乙個 pollfd的指標實現。

struct pollfd ;
pollfd結構包含了要監視的event和發生的event,不再使用select「引數-值」傳遞的方式。同時,pollfd並沒有最大數量限制(但是數量過大後效能也是會下降)。 和select函式一樣,poll返回後,需要輪詢pollfd來獲取就緒的描述符。從上面看,select和poll都需要在返回後,通過遍歷檔案描述符來獲取已經就緒的socket。事實上,同時連線的大量客戶端在一時刻可能只有很少的處於就緒狀態,因此隨著監視的描述符數量的增長,其效率也會線性下降。

epoll是在2.6核心中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加靈活,沒有描述符限制。epoll使用乙個檔案描述符管理多個描述符,將使用者關係的檔案描述符的事件存放到核心的乙個事件表中,這樣在使用者空間和核心空間的copy只需一次。

int epoll_create(int size);//建立乙個epoll的控制代碼,size用來告訴核心這個監聽的數目一共有多大

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

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

int epoll_create(int size);

建立乙個epoll的控制代碼,size用來告訴核心這個監聽的數目一共有多大,這個引數不同於select()中的第乙個引數,給出最大監聽的fd+1的值,引數size並不是限制了epoll所能監聽的描述符最大個數,只是對核心初始分配內部資料結構的乙個建議。

當建立好epoll控制代碼後,它就會占用乙個fd值,在linux下如果檢視/proc/程序id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須呼叫close()關閉,否則可能導致fd被耗盡。

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

函式是對指定描述符fd執行op操作。

struct epoll_event ;

//events可以是以下幾個巨集的集合:

epollin :表示對應的檔案描述符可以讀(包括對端socket正常關閉);

epollout:表示對應的檔案描述符可以寫;

epollpri:表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);

epollerr:表示對應的檔案描述符發生錯誤;

epollhup:表示對應的檔案描述符被結束通話;

epollet: 將epoll設為邊緣觸發(edge triggered)模式,這是相對於水平觸發(level triggered)來說的。

epolloneshot:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到epoll佇列裡

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

等待epfd上的io事件,最多返回maxevents個事件。

引數events用來從核心得到事件的集合,maxevents告之核心這個events有多大,這個maxevents的值不能大於建立epoll_create()時的size,引數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函式返回需要處理的事件數目,如返回0表示已超時。

epoll對檔案描述符的操作有兩種模式:lt(level trigger)和et(edge trigger)。lt模式是預設模式,lt模式與et模式的區別如下:

lt模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程式,應用程式可以不立即處理該事件。下次呼叫epoll_wait時,會再次響應應用程式並通知此事件。

et模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程式,應用程式必須立即處理該事件。如果不處理,下次呼叫epoll_wait時,不會再次響應應用程式並通知此事件。

I O多路復用之poll

poll的優點 1 poll 不要求開發者計算最大檔案描述符加一的大小。2 poll 在應付大數目的檔案描述符的時候速度更快,相比於select。3 它沒有最大連線數的限制,原因是它是基於鍊錶來儲存的。poll的缺點 1 大量的fd的陣列被整體複製於使用者態和核心位址空間之間,而不管這樣的複製是不是...

I O多路復用之select

阻塞i o模型 應用程式呼叫乙個i o函式,應用程式會一直等待資料準備好。如果資料沒有準備好,就會一直等待。只有當資料準備好,從核心拷貝到使用者空間io函式才成功返回。非阻塞i o模型 把乙個套介面設定成非阻塞告訴核心,當所有的i o操作無法完成時,不要將程序睡眠,而返回乙個錯誤資訊。此時i o操作...

IO多路復用之select

1 背景知識 我們首先來看看伺服器程式設計的模型,客戶端發來的請求服務端會產生乙個程序來對其進行服務,每當來乙個客戶請求就產生乙個程序來服務,然而程序不可能無限制的產生,因此為了解決大量客戶端訪問的問題,引入了io復用技術。即 乙個程序可以同時對多個客戶請求進行服務。也就是說io復用的 介質 是程序...