I/O多路轉(zhuǎn)接之select(只負責等)
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供赤坎網(wǎng)站建設(shè)、赤坎做網(wǎng)站、赤坎網(wǎng)站設(shè)計、赤坎網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、赤坎企業(yè)網(wǎng)站模板建站服務(wù),十余年赤坎做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
系統(tǒng)提供select函數(shù)來實現(xiàn)多路復用輸入/輸出模型。
傳向select的參數(shù)告訴內(nèi)核:
1)我們所關(guān)心的文件描述符。
參數(shù)nfds是需要監(jiān)視的最大的文件描述符值+1;
2)對每個描述符,我們所關(guān)心的狀態(tài)。
rdset,wrset,exset分別對應(yīng)于需要檢測的可讀文件描述符的集合,可寫文件描述符的集合及異常文件描述符的集合。
監(jiān)視的文件描述符分為三類set,每一種對應(yīng)等待不同的事件。readfds中列出的文件描述符被監(jiān)視是否有數(shù)據(jù)可供讀?。ㄈ绻x取操作完成則不會 阻 塞)。writefds中列出的文件描述符則被監(jiān)視是否寫入操作完成而不阻塞后,exceptfds中列出的文件描述符則被監(jiān)視是否發(fā)生異常,或者無 法控制的數(shù)據(jù)是否可用(這些狀態(tài)僅僅應(yīng)用于套接字)。這三類set可以是NULL,這種情況下select()不監(jiān)視這一類事件。
下面的宏提供了處理這三種描述詞組的方式:
FD_ZERO移除指定set中的所有文件描述符。每一次調(diào)用select()之前都應(yīng)該先調(diào)用它;
FD_CLR則從指定的set中移除一個文件描述符;
FD_SET添加一個文件描述符到指定的set中;
FD_ISSET測試一個文件描述符是否指定set的一部分。如果文件描述符在set中則返回一個非0整數(shù),不在則返0,F(xiàn)D_ISSET在調(diào)用select() 返回之后使用,測試指定的文件描述符是否準備好相關(guān)動作。
3)我們要等待多長時間。(我們可以等待無限長的時間,等待固定的一段時間,或者根本就不等待)
timeout參數(shù)是一個指向timeval結(jié)構(gòu)體的指針,timeval定義如下:
struct timeval結(jié)構(gòu)用于描述一段時間長度,如果在這個時間內(nèi),需要監(jiān)視的描述符沒有事件發(fā)生則函數(shù)返回,返回值為0。
從 select函數(shù)返回后,內(nèi)核告訴我們以下信息:
1)已經(jīng)做好準備的描述符的個數(shù)。
2)對于三種條件哪些描述符已經(jīng)做好準備。(讀,寫,異常)
執(zhí)成功則返回件描述詞狀態(tài)已改變的個數(shù);如果返回0代表在描述詞狀態(tài)改變前已超過timeout時間,沒有返回;
當有錯誤發(fā)時則返回-1,錯誤原因存于errno,此時參數(shù)readfds,writefds,exceptfds和timeout的值變成不可預測。錯誤值可能為:EBADF 件描述詞為效的或該件已關(guān)閉 ,EINTR 此調(diào)被信號所中斷 EINVAL 參數(shù)n 為負值,ENOMEM 核內(nèi)存不。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<arpa/inet.h> int fds[64]; const fds_nums=sizeof(fds)/sizeof(fds[0]); static int startup(const char* _ip,int _port) { int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } int opt=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(_port); local.sin_addr.s_addr=inet_addr(_ip); if(bind(sock,(struct sockaddr*)&local, sizeof(local))<0) { perror("bind"); exit(3); } if(listen(sock,5)<0) { perror("listen"); exit(4); } return sock; } static void usage(const char* _proc) { printf("Usage:%s[IP] [PORT]\n",_proc); } int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); exit(1); } int i=0; for(i=0;i<fds_nums;++i) { fds[i]=-1; } int listen_sock=startup(argv[1],atoi(argv[2])); fd_set rset; FD_ZERO(&rset); FD_SET(listen_sock,&rset); fds[0]=listen_sock; int done=0; while(!done) { int max_fd=-1; for(i=0;i<fds_nums;++i) { if(fds[i]>0) { FD_SET(fds[i],&rset); max_fd=max_fd<fds[i]?fds[i]:max_fd; } } struct timeval timeout={0,0}; switch(select(max_fd+1,&rset,NULL,NULL,NULL/*&timeout*/)) { case 0: printf("timeout..\n"); break; case 1: perror("select"); break; default: for(i=0;i<fds_nums;++i) { if(i=0&& FD_ISSET(listen_sock,&rset)) { struct sockaddr_in peer; socklen_t len=sizeof(peer); int new_fd=accept(listen_sock,(struct sockaddr*)&peer,&len); if(new_fd>0) { printf("get a new client:socket->%s:%d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port)); int j=0; for(j=0;j<fds_nums;j++) { if(fds[i]==-1) { fds[j]=new_fd; break; } } if(j==fds_nums) { close(new_fd); } } else { if(FD_ISSET(fds[i],&rset)) { char buf[1024]; memset(buf,'\0',sizeof(buf)); ssize_t _s=read(fds[i],buf,sizeof(buf)-1); if(_s>0) { printf("client# %s\n",buf); } else if(_s==0) { printf("client close...\n"); close(fds[i]); } else { perror("read"); } } } } } break; } } return 0; }
select優(yōu)點:
(1)相較于之前多線程的方法,使用select不用創(chuàng)建線程,更方便
(2)select目前幾乎在所有的平臺上都支持,其良好跨平臺支持也是它的一個優(yōu)點
select缺點:
(1)每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個開銷在fd很多時會很大
(2)同時每次調(diào)用select都需要在內(nèi)核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
(3)能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在Linux上一般為1024,因為它依賴于文件系統(tǒng)
(4)select()所維護的文件描述符的數(shù)據(jù)結(jié)構(gòu),隨著文件描述符數(shù)量的增大,其復制的開銷也線性增長。
(5)由于網(wǎng)絡(luò)響應(yīng)時間的延遲使得大量TCP連接處于非活躍狀態(tài),但調(diào)用select()會對所有socket進行一次線性掃描,這也會有一些開銷
網(wǎng)站標題:I/O多路轉(zhuǎn)接之select
文章網(wǎng)址:http://chinadenli.net/article36/gphgsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、軟件開發(fā)、小程序開發(fā)、電子商務(wù)、微信公眾號、ChatGPT
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)