select函數(shù):
#include <sys/select.h>#include <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);
參數(shù)含義:
返回值:
當(dāng)返回大于0的正值:監(jiān)視的文件集合中的文件描述符符合上述要求。
當(dāng)?shù)扔?時(shí):超時(shí)。
當(dāng)為-1時(shí):發(fā)生錯誤
struct timeval結(jié)構(gòu):
struct timeval{ time_t tv_sec; //秒 long tv_usec; // 微秒,即1/1000000s}
另外,還有4個宏操作文件描述符的集合:
FD_ZERO():清理文件描述符集合;
FD_SET():向某個文件描述符集合中加入文件描述符;
FD_CLR():從某個文件描述符集合中取某個文件描述符;
FD_ISSET():測試某個文件描述符是否為某個集合中的一員。
注:文件描述符的集合存在最大的限制,其最大值為FD_SETSIZE,當(dāng)超出最大值時(shí),發(fā)生不可預(yù)料的事。同時(shí),可以修改這個值,但是監(jiān)視集合的效率會降低,是因?yàn)閟elect()輪詢是線性的。在這里,有個更加牛B的的函數(shù),請查看epoll:epoll沒有最大并發(fā)連接的限制,上限是最大可以打開文件的數(shù)目,這個數(shù)字一般遠(yuǎn)大于2048, 一般來說這個數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。最大的優(yōu)點(diǎn)就在于它只管你“活躍”的連接,而跟連接總數(shù)無關(guān),因此在實(shí)際的網(wǎng)絡(luò)環(huán)境中,epoll的效率就會遠(yuǎn)遠(yuǎn)高于select和poll。在內(nèi)存拷貝上,epoll在這點(diǎn)上使用了“共享內(nèi)存”,這個內(nèi)存拷貝也省略了。
附加:使用select()寫的IO復(fù)用循環(huán)服務(wù)器模型的例子
1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <time.h> 5 #include <string.h> 6 #include <stdio.h> 7 #include <pthread.h> 8 #include <sys/select.h> 9 #define BUFFLEN 1024 10 #define SERVER_PORT 8888 11 #define BACKLOG 5 12 #define CLIENTNUM 1024/*最大支持客戶端數(shù)量*/ 13 14 /*可連接客戶端的文件描述符數(shù)組*/ 15 int connect_host[CLIENTNUM]; 16 int connect_number = 0; 17 18 //處理客戶端請求函數(shù) 19 static void *handle_request(void *argv) 20 { 21 time_t now; /*時(shí)間*/ 22 char buff[BUFFLEN];/*收發(fā)數(shù)據(jù)緩沖區(qū)*/ 23 int n = 0; 24 25 int maxfd = -1;/*最大偵聽文件描述符*/ 26 fd_set scanfd; /*偵聽描述符集合*/ 27 struct timeval timeout; /*超時(shí)*/ 28 timeout.tv_sec = 1; /* 阻塞1秒后超時(shí)返回 */ 29 timeout.tv_usec = 0; 30 31 int i = 0; 32 int err = -1; 33 for(;;) 34 { 35 /*最大文件描述符值初始化為-1*/ 36 maxfd = -1; 37 FD_ZERO(&scanfd);/*清零文件描述符集合*/ 38 for(i=0;i<CLIENTNUM;i++)/*將文件描述符放入集合*/ 39 { 40 if(connect_host[i] != -1)/*合法的文件描述符*/ 41 { 42 FD_SET(connect_host[i], &scanfd);/*放入集合*/ 43 if(maxfd < connect_host[i])/*更新最大文件描述符值*/ 44 { 45 maxfd = connect_host[i]; 46 } 47 } 48 } 49 /*select等待*/ 50 err = select(maxfd + 1, &scanfd, NULL, NULL, &timeout) ; 51 switch(err) 52 { 53 case 0:/*超時(shí)*/ 54 break; 55 case -1:/*錯誤發(fā)生*/ 56 break; 57 default:/*有可讀套接字文件描述符*/ 58 if(connect_number<=0) 59 break; 60 for(i = 0;i<CLIENTNUM;i++) 61 { 62 /*查找激活的文件描述符*/ 63 if(connect_host[i] != -1) 64 if(FD_ISSET(connect_host[i],&scanfd)) 65 { 66 memset(buff, 0, BUFFLEN);/*清零*/ 67 n = recv(connect_host[i], buff, BUFFLEN,0);/*接收發(fā)送方數(shù)據(jù)*/ 68 if(n > 0 && !strncmp(buff, "TIME", 4))/*判斷是否合法接收數(shù)據(jù)*/ 69 { 70 memset(buff, 0, BUFFLEN);/*清零*/ 71 now = time(NULL);/*當(dāng)前時(shí)間*/ 72 sPRintf(buff, "%24s/r/n",ctime(&now));/*將時(shí)間拷貝入緩沖區(qū)*/ 73 send(connect_host[i], buff, strlen(buff),0);/*發(fā)送數(shù)據(jù)*/ 74 } 75 /*更新文件描述符在數(shù)組中的值*/ 76 connect_host[i] = -1; 77 connect_number --; /*客戶端計(jì)數(shù)器減1*/ 78 /*關(guān)閉客戶端*/ 79 close(connect_host[i]); 80 } 81 } 82 break; 83 } 84 } 85 86 return NULL; 87 } 88 89 //處理客戶端連接函數(shù) 90 static void *handle_connect(void *argv) 91 { 92 int s_s = *((int*)argv) ;/*獲得服務(wù)器偵聽套接字文件描述符*/ 93 int s_c = -1;/*連接客戶端文件描述符*/ 94 struct sockaddr_in from; 95 int len = sizeof(from); 96 /*接收客戶端連接*/ 97 for(;;) 98 { 99 int i = 0;100 int s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客戶端的請求*/101 printf("a client connect, from:%s/n",inet_ntoa(from.sin_addr));102 /*查找合適位置,將客戶端的文件描述符放入*/ 103 for(i=0;i<CLIENTNUM;i++)104 {105 if(connect_host[i] == -1)/*找到*/106 {107 /*放入*/108 connect_host[i]= s_c;109 110 /*客戶端計(jì)數(shù)器加1*/111 connect_number ++;112 /*繼續(xù)輪詢等待客戶端連接*/113 break; 114 } 115 } 116 } 117 return NULL;118 }119 120 int main(int argc, char *argv[])121 {122 int s_s; /*服務(wù)器套接字文件描述符*/123 struct sockaddr_in local; /*本地地址*/ 124 int i = 0;125 memset(connect_host, -1, CLIENTNUM);126 127 /*建立TCP套接字*/128 s_s = socket(AF_INET, SOCK_STREAM, 0);129 130 /*初始化地址接哦股*/131 memset(&local, 0, sizeof(local));/*清零*/132 local.sin_family = AF_INET;/*AF_INET協(xié)議族*/133 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/134 local.sin_port = htons(SERVER_PORT);/*服務(wù)器端口*/135 136 /*將套接字文件描述符綁定到本地地址和端口*/137 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));138 err = listen(s_s, BACKLOG);/*偵聽*/139 140 pthread_t thread_do[2];/*線程ID*/141 /*創(chuàng)建線程處理客戶端連接*/142 pthread_create(&thread_do[0],/*線程ID*/143 NULL,/*屬性*/144 handle_connect,/*線程回調(diào)函數(shù)*/145 (void*)&s_s); /*線程參數(shù)*/146 /*創(chuàng)建線程處理客戶端請求*/ 147 pthread_create(&thread_do[1],/*線程ID*/148 NULL,/*屬性*/149 handle_request,/*線程回調(diào)函數(shù)*/150 NULL); /*線程參數(shù)*/151 /*等待線程結(jié)束*/152 for(i=0;i<2;i++)153 pthread_join(thread_do[i], NULL);154 155 close(s_s);156 157 return 0; 158 }
作者:orange1438出處:http://www.CUOXin.com/orange1438/本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
新聞熱點(diǎn)
疑難解答
圖片精選