linux—I/O多路轉接之select

【I/O多路轉接】
socket中讀取數據可以使用如下的代碼:

while( (n = read(socketfd, buf, BUFSIZE) ) >0)

if( write(STDOUT_FILENO, buf, n) = n)

{

printf(“write error”);

exit(1);

}

當代碼中的socketfd描述符所對應的文件表項是處於阻塞時,它會一直阻塞,直到有數據從網絡的另一端發送過來。如果它是一個服務器程序,它要讀寫大量的socket,那麼在某一個socket上的阻塞很明顯會影響與其它socket的交互過程。類似的問題不單單出現在網絡上,還可以出現在讀寫加鎖的文件和FIFO等等一系列的情況。

一種比較好的解決方法似乎是採用非阻塞IO來實現。把所要讀取數據的socketfd設置爲非阻塞狀態,依次用read函數檢查是否有數據到來,如有,它會返回接到數據的個數,否則它會返回-1以表示當前還沒有數據到達。這樣,對於每個socket,如有數據到來則讀取,沒有也會馬上返回。這就是非阻塞IO的好處拉。部分代碼如下:

//clientfd[]爲客戶端的socket描述符組數,假設數組的大小爲MAX,並且所有客戶端socket描述符都設置爲非阻塞狀態時。

for(i = 0; i < MAX; ++i)

{

int n;

if( (n = read(clientfd[i], buf, SZIE)) >0)

{

//send response to client in here.

}

}

這裏代碼看起來與上面的代碼沒有太大的區別,其實是有很大的區別;區別就是使使用了非阻塞IO進行整個交互過程,使得各個客戶端都得到相對平等的時間待遇。這種模式我們通常稱爲這“輪詢”模式。輪詢模式同樣有它的不足之處,在執行read函數時,實際上大部分時間還是沒有數據可讀的,但仍不斷地執行read,浪費了很多CPU時間。


       I/O多路轉接(I/O multiplexing)就可以解決上述的問題。它可謂是上面兩種方法的接衷:先構造一張有關描述符的數據表,然後調用一個函數,僅當有一個或多個描述符已準備可以進行IO操作時才返回,否則一直阻塞。在返回時,它會告訴進程那些描述符已準備好可以進行IO

【select函數】

函數的功能:實現多路轉接,通過調用內核來實現。它向內核提供如下的參數

1)我們所關心的描述符

2)對於每個描述符,我們所關心的條件(是否讀一個給定的描述符,還是想寫一個給定的描述符,還是關心一個描述符的異常條件)

3)希望等待多久時間(可以永遠等待,等待一個固定時間,或完全不等待)

select返回時,內核告訴我們:

1)已準備好的描述符數量

2)哪一個描述符已準備好讀、寫或異常條件

使用這種返回值,就可調用相應的I/O函數,通常是readwrite,並確知該函數不會阻塞。

【編寫select】

【代碼結果】
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章