select的功能可以用一句話來描述:
實現基於i/o多路復用的非同步併發程式設計。
在具體講解select之前我們先看看常規的阻塞socket程式設計方式,以服務端為例:
對於這種方式,最大的問題在**呢?accept和recev的阻塞呼叫!下面以兩種場景為例,來說明相比這種情況,select是如何做到非同步i/o多路復用的高效性。
第一種場景:server除了要對外響應client的服務外,還要能夠接受標準輸入的命令來進行管理。
假如使用上述阻塞方式,在單執行緒中,accept呼叫和read呼叫必定有先後順序,而它們都是阻塞的。比如先呼叫accept,後呼叫 read,那麼如果沒有客戶請求時,伺服器會一直阻塞在accept,沒有機會呼叫read,也就不能響應標準輸入的命令。
1
int
fd_stdin = open(...);
2
int
fd_socket = socket(...);
3
bind(...);
4
listen(...);
5
while
(1)
而如果使用select,先註冊分別由socket和open建立的檔案描述符,然後進入select呼叫。當其中任何乙個檔案描述符的狀態發生改變時,就可以進行相應的處理。
01
int
fd_stdin = open(...);
02
int
fd_socket = socket(...);
03
bind(...);
04
listen(...);
05
fd_set fs;
06
while
(1)
第二種場景:server要對外提供大量的client請求服務。
假如使用阻塞方式,在單執行緒中,由於accept和recev都是阻塞式的,那麼當乙個client被伺服器accept後,它可能在send傳送訊息時阻塞,因此伺服器就會阻塞在recev呼叫。即時此時有其他的client進行connect,也無法進行響應。
1
int
fd_socket = socket(...);
2
bind(...);
3
listen(...);
4
while
(1)
而如果使用select,在伺服器端先註冊由socket建立的檔案描述符,然後進入select呼叫。只有當由socket建立的檔案描述符的狀態發生改變時,才執行accept操作,並把得到的client的檔案描述符進行註冊,再次進入select呼叫。當select檢查到有檔案描述符的狀態改變時,如果是server的socket建立的檔案描述符,則執行accept操作,否則執行recev操作。當請求的client數目比較多時, select明顯能夠提高併發性。
01
int
fd_socket = socket(...);
02
bind(...);
03
listen(...);
04
fd_set fs;
05
while
(1)
14
15
if
(fd_isset(fd_accept...))
16
recv(...);
17
}
說完了select相比阻塞呼叫的好處,我們也簡單說說它的限制和不足。
(1)select在查詢狀態改變的檔案描述符時,是對描述符鍊錶進行遍歷操作,因此對效率有較大影響。
(2)select在預設情況下,支援的最大檔案描述符個數為1024。當然,可以通過修改linux的socket核心進行修改。
I O多路復用之select
阻塞i o模型 應用程式呼叫乙個i o函式,應用程式會一直等待資料準備好。如果資料沒有準備好,就會一直等待。只有當資料準備好,從核心拷貝到使用者空間io函式才成功返回。非阻塞i o模型 把乙個套介面設定成非阻塞告訴核心,當所有的i o操作無法完成時,不要將程序睡眠,而返回乙個錯誤資訊。此時i o操作...
IO多路復用之select
1 背景知識 我們首先來看看伺服器程式設計的模型,客戶端發來的請求服務端會產生乙個程序來對其進行服務,每當來乙個客戶請求就產生乙個程序來服務,然而程序不可能無限制的產生,因此為了解決大量客戶端訪問的問題,引入了io復用技術。即 乙個程序可以同時對多個客戶請求進行服務。也就是說io復用的 介質 是程序...
I O多路復用之select
select是用於監視多個檔案描述符狀態的變化的。即用來監視檔案描述符讀 寫 異常狀態是否就緒。函式原型 int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout select...