I O多路轉接之select

2021-08-21 15:59:45 字數 3899 閱讀 5830

一:什麼是多路轉接?什麼是select?

簡單來說,select只做一件事,那就是等,等至少乙個檔案描述符的讀寫時間就緒。

具體來講,系統提供select來實現多路復用輸入/輸出模型:

select系統呼叫可以讓程式監視多個檔案描述符的狀態變化;

程式會在select這裡等待,直到被監視的檔案描述符至少有乙個發生了狀態改變。

select函式宣告

引數解釋:

① nfds:被監視的最大檔案描述符的值+1;

② readfds:只關心讀事件,可讀檔案描述符的集合;

writefds:只關心寫事件,可寫檔案描述符的集合;

exceptfds:只關心異常事件,異常檔案描述符的集合;

fd_set的結構:

fd_set就是乙個位圖,點陣圖中的位置代表對應的檔案描述符,用0或1來控制。

但是,我們不能直接操作fd_set,而是要呼叫函式:

void fd_zero(fd_set &set);//清除set的全部位

void fd_set(int fd, fd_set &set);//把fd設定進set的相關位

void fd_clr(int fd, fd_set &set);//把fd在set的相關位清除

int fd_isset(int fd, fd_set &set);//判斷fd是否被set設定進相關位

timeval的結構:

返回值解釋:

執行成功則返回已改變狀態的檔案描述符的個數;

返回0表示timeout超時;

返回-1則表示發生了錯誤。

簡單描述select的執行過程:

.為了方便說明,假設fd_set的長度為1位元組,則一位元組中最大可以對應8個檔案描述符。

1.fd_set set;fdzero(&set);此時set為0000 0000;

2.若fd=5,執行fd_set(fd,&set);此時set變為0001 0000;

3.再加上1和2檔案描述符,則set變為0001 0011;

4.執行select(6,&set,0,0,0)

5.若1和2發生了可讀事件,則select返回,此時set為0000 0011,因為5沒有發生事件,所以對應位置被清空。

編寫select**:

一.檢測標準輸入:

int main

() if(fd_isset(0,&read_fds));

read(0,buf,sizeof(buf)-1);

printf("input: %s\n",buf);

}else

fd_zero(&read_fds);

fd_set(0,&read_fds);

}return

0;}

此時的執行效果為,直到在標準輸入上輸入之前,select都會一直阻塞的等待。

二.模擬實現select伺服器

int main(int argc,char* argv)

int listen_sock = socket(af_inet,sock_stream,0);

if(listen_sock < 0)

struct sockaddr_in local;

local.sin_family = af_inet;

local.sin_addr.s_addr = inet_addr(argv[1]);

local.sin_port = htons(atoi(argv[2]));

if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0)

if(listen(listen_sock,5) < 0)

//陣列的大小就是fd_set這個位圖能夠存多少個fd,因為需要用陣列記錄

int fdarray[sizeof(fd_set)*8];

//把listen_sock給陣列的第乙個元素

fdarray[0] = listen_sock;

int num = sizeof(fdarray)/sizeof(fdarray[0]);//最多存1024個fd

//printf("%d\n",num);

//之後的初始化該為-1

int i = 0;

for(i = 1 ; i1;

}while(1)

}// struct timeval timeout = ;

switch(select(maxfd+1,&rfds,null,null,null))

//遇見-1就說明處理完了

for(i = 0; iif(fdarray[i] == -1)

break;

} //new_sock必須在範圍之內

if(i < num)

fdarray[i] = new_sock;

else

continue;}}

if(fd_isset(fdarray[i],&rfds))

else

if(s == 0)

else}}

}}return

0;}

客戶端:

int main(int argc,char* argv)

struct sockaddr_in server;

server.sin_family = af_inet;

server.sin_addr.s_addr = inet_addr(argv[1]);

server.sin_port = htons(atoi(argv[2]));

int fd = socket(af_inet,sock_stream,0);

if(fd < 0)

int ret = connect(fd,(struct sockaddr*)&server,sizeof(server));

if(ret < 0)

while(1);

read(0,buf,sizeof(buf)-1);

ssize_t s = write(fd,buf,strlen(buf));

if(s < 0)

}close(fd);

return

0;}

select的缺點:1.可監控檔案描述符的個數太小,取決於sizeof(fdset)的大小,我的sizeof(fdset)僅為1024,所以最大的檔案描述符為1024*8;

2.將fd加入集合點陣圖的同時,還需要再用陣列儲存已被監控的檔案描述符,原因是:

select返回後,把以前加入但無事件發生的fd清空,則每次select前都要重新從陣列取fd逐一加入,再取fd最大值 作為第乙個引數,很是麻煩;

3.引數即輸入又作輸出;

4.需要把fd集合從使用者態拷貝至核心態,開銷很大。

I O多路轉接之select

什麼是i o多路轉接技術 先構建一張有關描述符的列表,然後呼叫乙個函式,直到這些描述符中的乙個已準備好進行i o時,該函式才返回,在返回時,他告訴程序哪些描述符已準備好可以進行i o。上述呼叫的函式,有select,poll,pselect及poll的增強版epoll等,本文主要介紹select。函...

I O多路轉接之select

下面的巨集提供了處理fd set的這三種描述集的方式 fd clr inr fd,fd set set 用來清除描述片語set中相關fd 的位 fd isset int fd,fd set set 用來測試描述片語set中相關fd 的位是否為真 fd set int fd,fd set set 用來...

IO多路轉接之select

系統提供select函式來實現多路轉接。呼叫select函式介面的特點 一次需要等待多個檔案描述符。select函式原型 include include include int select int nfds,fd set readfds,fd set writefds,fd set exceptf...