經(jīng)過(guò)幾天對(duì)I/O復(fù)用這章內(nèi)容的學(xué)習(xí),了解select、pselect、poll函數(shù)
I/O復(fù)用主要用于有多個(gè)描述字的場(chǎng)合,在前面的回射程序的學(xué)習(xí)當(dāng)中,我們可以發(fā)現(xiàn)客戶(hù)端程序要處理2個(gè)描述字,
其中一個(gè)是用于處理客戶(hù)端的標(biāo)準(zhǔn)輸入
另外一個(gè)是用于處理套接口傳遞過(guò)來(lái)的數(shù)據(jù)
基于上面的情況,我們可以發(fā)現(xiàn)有這樣一種情況,如果服務(wù)端程序提前斷開(kāi),例如輸入ctrl+C,那么客戶(hù)端程序依然阻塞于
標(biāo)準(zhǔn)輸入,即等待用戶(hù)輸入,但這時(shí)輸入已經(jīng)毫無(wú)意義,因?yàn)榉?wù)器程序已經(jīng)停止工作了;
這章的幾個(gè)函數(shù)就是用于處理這種情況的,即當(dāng)任何一個(gè)描述字當(dāng)前的狀態(tài)為準(zhǔn)備好,那么程序就可以處理它,而不是一直
阻塞于未準(zhǔn)備好的描述字
在unix中有5個(gè)基本的I/O模型
1、阻塞I/O
2、非阻塞I/O
3、I/O復(fù)用
4、信號(hào)驅(qū)動(dòng)I/O
5、異步I/O
我們這章主要用的是I/O復(fù)用(select/poll),其他的I/O模型在這里就不介紹了!
我們阻塞于select調(diào)用,等待數(shù)據(jù)報(bào)套接口可讀,當(dāng)select返回套接口可讀的條件時(shí),我們調(diào)用recvfrom將數(shù)據(jù)報(bào)拷貝到應(yīng)用緩沖區(qū)中
使用它的好處是我們可以等待多個(gè)描述字準(zhǔn)備好
下面簡(jiǎn)單介紹一下select函數(shù)的幾個(gè)參數(shù)說(shuō)明
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *errorfds, struct timeval *timeout);
還是按照書(shū)上說(shuō)的順序簡(jiǎn)單介紹下幾個(gè)參數(shù)的含義
1、timeout參數(shù)是描述字準(zhǔn)備要花費(fèi)的時(shí)間,有三種取值(NULL,{*,*},{0,0}),具體的可自行查找,就不做詳細(xì)的介紹了
2、readfds,writefds,errorfds指定我們要讓內(nèi)核測(cè)試讀、寫(xiě)和異常條件所需的描述字,類(lèi)型是集合類(lèi)型的,可以用以下幾個(gè)函數(shù)對(duì)其進(jìn)行操作
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是指定被測(cè)試的描述字的個(gè)數(shù),它的值是最大描述字的值加1
下面的表格是摘自書(shū)上的小結(jié)
其中待處理錯(cuò)誤和TCP外帶數(shù)據(jù)還是有點(diǎn)不理解
在了解了這個(gè)函數(shù)之后,作者就對(duì)前面的回射程序的客戶(hù)端輸出str_cli進(jìn)行修改,使其能檢測(cè)多個(gè)描述字的狀態(tài),并在服務(wù)器退出后能迅速退出,而不是阻塞在等待標(biāo)準(zhǔn)輸入的輸入
下面就是幾個(gè)關(guān)鍵的代碼片斷
fp代表標(biāo)準(zhǔn)輸入的描述字
sockfd代表套接口的描述字
rset代表描述字集合




















下面為了改造程序,使其能夠進(jìn)行批量輸入,即能一次輸入多行,還要了解2個(gè)函數(shù)shutdown和close
區(qū)別:
1、close將描述字的訪問(wèn)計(jì)數(shù)減一,僅在計(jì)數(shù)器為0時(shí)關(guān)閉套接口
2、close終止了數(shù)據(jù)傳送的2個(gè)方向:讀和寫(xiě),而shutdown可以只終止一個(gè)方向的連接,這就是其參數(shù)howto設(shè)置的
howto的選項(xiàng)有如下幾種:
1、SHUT_RD -->關(guān)閉連接的讀的一半
2、SHUT_WR -->關(guān)閉連接的寫(xiě)的一半
3、SHUT_RDWR -->連接的寫(xiě)一半和讀一半都關(guān)閉
作者是通過(guò)改造str_cli的函數(shù)來(lái)介紹shutdown和select的使用的,但書(shū)上的例子中少了個(gè)關(guān)鍵字else,導(dǎo)致輸入一行就輸出一行,沒(méi)有批量輸入的現(xiàn)象,查了很長(zhǎng)時(shí)間才找到那個(gè)丟失的else(第12行)
但是我發(fā)現(xiàn),這個(gè)批量輸入只能進(jìn)行輸入一次操作,當(dāng)我輸入ctrl+d的時(shí)候,輸出了以前輸入的多行,但是程序就退出了(需要改造,思考中)
這個(gè)程序的主要思想就是,通過(guò)一開(kāi)關(guān)先對(duì)標(biāo)準(zhǔn)輸入進(jìn)行select操作(FD_SET(fileno(fp),&rset)),當(dāng)輸入ctrl+d,開(kāi)關(guān)關(guān)閉,關(guān)閉連接的寫(xiě)這一半(shutdown(sockfd,SHUT_WR);),清除select中對(duì)標(biāo)準(zhǔn)輸入的操作的標(biāo)志(FD_CLR(fileno(fp),&rset);),設(shè)置select對(duì)套接口的操作(FD_SET(sockfd,&rset);).......
這就是對(duì)select的簡(jiǎn)單介紹和一些應(yīng)用,不能一次寫(xiě)的太多,下次再說(shuō)下如何利用select替代服務(wù)端的fork操作......