linux網路編程之socket(八):五種I/O模型和select函數簡介

來源:互聯網
上載者:User

一、五種I/O模型

1、阻塞I/O

我們在前面所說的I/O模型都是阻塞I/O,即調用recv系統調用,如果沒有資料則阻塞等待,當資料到來則將資料從核心空間(套介面緩衝區)拷貝到使用者空間(recv函數提供的buf),然後recv返回,進行資料處理。


2、非阻塞I/O


我們可以使用 fcntl(fd, F_SETFL, flag | O_NONBLOCK); 將通訊端標誌變成非阻塞,調用recv,如果裝置暫時沒有資料可讀就返回-1,同時置errno為EWOULDBLOCK(或者EAGAIN,這兩個宏定義的值相同),表示本來應該阻塞在這裡(would
block,虛擬語氣),事實上並沒有阻塞而是直接返回錯誤,調用者應該試著再讀一次(again)。這種行為方式稱為輪詢(Poll),調用者只是查詢一下,而不是阻塞在這裡死等,這樣可以同時監視多個裝置:

while(1) 

非阻塞read(裝置1); 

if(裝置1有資料到達) 

處理資料; 

非阻塞read(裝置2); 

if(裝置2有資料到達) 

處理資料; 

..............................

}


如果read(裝置1)是阻塞的,那麼只要裝置1沒有資料到達就會一直阻塞在裝置1的read調用上,即使裝置2有資料到達也不能處理,使用非阻塞I/O就可以避免裝置2得不到及時處理。

非阻塞I/O有一個缺點,如果所有裝置都一直沒有資料到達,調用者需要反覆查詢做無用功,如果阻塞在那裡,作業系統可以調度別的進程執行,就不會做無用功了,在實際應用中非阻塞I/O模型比較少用。

3、I/O複用

用select來管理多個I/O,當沒有資料時select阻塞,如果在逾時時間內資料到來則select返回,再調用recv進行資料的複製,recv返回後處理資料。

4、訊號驅動I/O

先註冊SIGIO訊號的處理函數,進程繼續執行其他動作,當資料到來時會發送SIGIO訊號給進程,然後可以在訊號處理函數中調用recv進行資料的複製,然後recv返回進行資料處理。

5、非同步I/O

aio_read 函數也會提供一個buf,系統調用進入核心,如果沒有資料則立即返回,進程繼續執行其他動作,所以叫非同步I/O,當資料到來時核心自動複製資料,然後推送給使用者空間,通過在aio_read中指定的訊號通知進程,讓其處理資料。非同步I/O跟訊號驅動I/O的不同之處在於,它不用調用recv進行資料的複製,如果將後者比做”拉pull“,則前者可以認為是”push推“,push的效率會高點,其實非同步I/O跟windows下面的完成連接埠差不多,但aio_read的實現或多或少存在問題,用得也比較少。

  

二、select函數簡介

/* According to POSIX.1-2001 */
       #include <sys/select.h>
       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

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


參數1:讀寫異常集合中的檔案描述符的最大值加1;

參數2:讀集合,關心可讀事件;

套介面緩衝區有資料可讀
串連的讀一半關閉,即接收到FIN段,讀操作將返回0
如果是監聽套介面,已完成串連隊列不為空白時。
套介面上發生了一個錯誤待處理,錯誤可以通過getsockopt指定SO_ERROR選項來擷取。

參數3:寫集合,關心可寫事件;

套介面發送緩衝區有空間容納資料。

串連的寫一半關閉。即收到RST段之後,再次調用write操作。

套介面上發生了一個錯誤待處理,錯誤可以通過getsockopt指定SO_ERROR選項來擷取。

參數4:異常集合,關心例外狀況事件;

套介面存在帶外資料(TCP頭部 URG標誌,16位緊急指標欄位)

參數5:逾時時間結構體

對於參數2,3,4來說,如果不關心對應事件則設定為NULL即可。注意5個參數都是輸入輸出參數,即select返回時可能對其進行了修改,比如集合被修改以便標記哪些套介面發生了事件,時間結構體的傳出參數是剩餘的時間,如果設定為NULL表示永不逾時。用select管理多個I/O,select阻塞等待,一旦其中的一個或多個I/O檢測到我們所感興趣的事件,select函數返回,傳回值為偵測到的事件個數,並且返回哪些I/O發送了事件,遍曆這些事件,進而處理事件。注意當select阻塞返回後,此時調用read/write
是不會阻塞的,因為正是有可讀可寫事件發生才導致select 返回,也可以認為是select 提前阻塞了。

下面是4個可以對集合進行操作的宏:
void FD_CLR(int fd, fd_set *set); // 清除出集合
int  FD_ISSET(int fd, fd_set *set); // 判斷是否在集合中
void FD_SET(int fd, fd_set *set); // 添加進集合中
void FD_ZERO(fd_set *set); // 將集合清零

select函數的舉例應用看這裡。

參考:

《Linux C 編程一站式學習》

《TCP/IP詳解 卷一》

《UNP》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.