經過幾天對I/O復用這章內容的學習,了解select、pselect、poll函數
I/O復用主要用于有多個描述字的場合,在前面的回射程序的學習當中,我們可以發現客戶端程序要處理2個描述字,
其中一個是用于處理客戶端的標準輸入
另外一個是用于處理套接口傳遞過來的數據
基于上面的情況,我們可以發現有這樣一種情況,如果服務端程序提前斷開,例如輸入ctrl+C,那么客戶端程序依然阻塞于
標準輸入,即等待用戶輸入,但這時輸入已經毫無意義,因為服務器程序已經停止工作了;
這章的幾個函數就是用于處理這種情況的,即當任何一個描述字當前的狀態為準備好,那么程序就可以處理它,而不是一直
阻塞于未準備好的描述字
在unix中有5個基本的I/O模型
1、阻塞I/O
2、非阻塞I/O
3、I/O復用
4、信號驅動I/O
5、異步I/O
我們這章主要用的是I/O復用(select/poll),其他的I/O模型在這里就不介紹了!
我們阻塞于select調用,等待數據報套接口可讀,當select返回套接口可讀的條件時,我們調用recvfrom將數據報拷貝到應用緩沖區中
使用它的好處是我們可以等待多個描述字準備好
下面簡單介紹一下select函數的幾個參數說明
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *errorfds, struct timeval *timeout);
還是按照書上說的順序簡單介紹下幾個參數的含義
1、timeout參數是描述字準備要花費的時間,有三種取值(NULL,{*,*},{0,0}),具體的可自行查找,就不做詳細的介紹了
2、readfds,writefds,errorfds指定我們要讓內核測試讀、寫和異常條件所需的描述字,類型是集合類型的,可以用以下幾個函數對其進行操作
void FD_CLR(int fd, fd_set *fdset);-->turn off the bit for fd in fd_set
int FD_ISSET(int fd, fd_set *fdset);-->is the bit for fd in fd_set?
void FD_SET(int fd, fd_set *fdset);-->turn on the bit for fd in fd_set
void FD_ZERO(fd_set *fdset);-->clear all bits in fd_set
3、nfds是指定被測試的描述字的個數,它的值是最大描述字的值加1
下面的表格是摘自書上的小結

其中待處理錯誤和TCP外帶數據還是有點不理解
在了解了這個函數之后,作者就對前面的回射程序的客戶端輸出str_cli進行修改,使其能檢測多個描述字的狀態,并在服務器退出后能迅速退出,而不是阻塞在等待標準輸入的輸入
下面就是幾個關鍵的代碼片斷
fp代表標準輸入的描述字
sockfd代表套接口的描述字
rset代表描述字集合
FD_ZERO(&rset);
FD_SET(fileno(fp),&rset);
FD_SET(sockfd,&rset);

maxfdp1=max(fileno(fp),sockfd)+1;//select的第一個參數,描述字中最大值加1
select(maxfdp1,&rset,NULL,NULL,NULL);

//完成上面的代碼以后就開始檢測各個描述字的狀態,看其是否可讀
if(FD_ISSET(fileno(fp),&rset)


{
//do something
}
if(FD_ISSET(sockfd,&rset)


{
//do something
}
下面為了改造程序,使其能夠進行批量輸入,即能一次輸入多行,還要了解2個函數shutdown和close
區別:
1、close將描述字的訪問計數減一,僅在計數器為0時關閉套接口
2、close終止了數據傳送的2個方向:讀和寫,而shutdown可以只終止一個方向的連接,這就是其參數howto設置的
howto的選項有如下幾種:
1、SHUT_RD -->關閉連接的讀的一半
2、SHUT_WR -->關閉連接的寫的一半
3、SHUT_RDWR -->連接的寫一半和讀一半都關閉
作者是通過改造str_cli的函數來介紹shutdown和select的使用的,但書上的例子中少了個關鍵字else,導致輸入一行就輸出一行,沒有批量輸入的現象,查了很長時間才找到那個丟失的else(第12行)
但是我發現,這個批量輸入只能進行輸入一次操作,當我輸入ctrl+d的時候,輸出了以前輸入的多行,但是程序就退出了(需要改造,思考中)
這個程序的主要思想就是,通過一開關先對標準輸入進行select操作(FD_SET(fileno(fp),&rset)),當輸入ctrl+d,開關關閉,關閉連接的寫這一半(shutdown(sockfd,SHUT_WR);),清除select中對標準輸入的操作的標志(FD_CLR(fileno(fp),&rset);),設置select對套接口的操作(FD_SET(sockfd,&rset);).......
這就是對select的簡單介紹和一些應用,不能一次寫的太多,下次再說下如何利用select替代服務端的fork操作......
posted on 2007-09-08 09:56
LG 閱讀(391)
評論(0) 編輯 收藏 引用 所屬分類:
UnixProgram