select系統調用用于一次監控多個句柄(文件描述符)的狀態變化的。程序會停在select處等待,直到被監視的句柄有一個或多個發生了狀態改變。
在成都網站制作、做網站中從網站色彩、結構布局、欄目設置、關鍵詞群組等細微處著手,突出企業的產品/服務/品牌,幫助企業鎖定精準用戶,提高在線咨詢和轉化,使成都網站營銷成為有效果、有回報的無錫營銷推廣。創新互聯建站專業成都網站建設10余年了,客戶滿意度97.8%,歡迎成都創新互聯客戶聯系。
select函數原型:
int select(int nfds, fd_set *readfds, fd_set *writefd,fd_set *exceptfds, struct timeval *timeout);
nfds:表示文件描述符集的個數
readfds:當前有多少個讀事件(有數據到了這個狀態稱之為讀事件)
writefd:當前有多少個寫事件(關心輸出緩沖區是否已滿)
最后一個結構體表示每個幾秒鐘醒來做其他事件,用來設置select等待時間
函數返回值:
執行成功返回描述符集當中狀態已改變的個數
返回0表示在描述符狀態改變前已經timeout
返回-1表示有錯誤發生,可能為某個套接字的帶有外數據到達
關于select函數的相關函數操作
FD_CLR(inr fd,fd_set* set);來清除描述詞組set中相關fd 的位
FD_ISSET(int fd,fd_set *set);判斷該文件描述符是否在當前文件描述符集中
FD_SET(int fd,fd_set*set);將該描述符設置到當前文件描述符集中
FD_ZERO(fd_set *set);可以用來初始化文件描述符集
select模型中的fd_set,例:若fd_set為1字節,共有8位,則它的每一個位都可以對應一個文件描述符,若fd=1則應為0000 0001
將fd加入select監控集時,要用一個數組保存放到select監控集中的文件描述符,為了在select 返回后,該數組中保存的數據可以和fd_set進行FD_ISSET判斷,select在返回后會把以前加入的但并無任何事件發生的fd清空,每次開始select前都要重新從數組取得fd
逐一加入。
使用select實現TCP通信
服務器端:
1 #include<stdio.h>
2 #include<string.h>
3 #include<errno.h>
4 #include<sys/select.h>
5 #include<stdlib.h>
6 #include<netinet/in.h>
7 #include<unistd.h>
8 #include<arpa/inet.h>
9 #include<sys/socket.h>
10 int fileds[64]; //用一個數組保存select監控集中的文件描述符
11 void Usage(const char* proc)
12 {
13 printf("Usage:%s [ip] [port]\n",proc);
14 }
15
16 int start(int port,char* ip)
17 {
18 int listen_sock=socket(AF_INET,SOCK_STREAM,0);
19 if(listen_sock<0)
20 {
21 perror("socket");
22 exit(1);
23 }
24 struct sockaddr_in local;
25 local.sin_family=AF_INET;
26 local.sin_port=htons(port);
27 local.sin_addr.s_addr=inet_addr(ip);
28 socklen_t len=sizeof(local);
29 if(bind(listen_sock,(struct sockaddr*)&local,len)<0)
30 {
31 perror("bind");
32 exit(2);
33 }
34 if(listen(listen_sock,5)<0)
35 {
36 perror("listen");
37 exit(3);
38 }
39 return listen_sock;
40 }
41 int main(int argc,char* argv[])
42 {
43 if(argc!=3)
44 {
45 Usage(argv[0]);
46 exit(1);
47 }
48 char* _ip=argv[1];
49 int _port=atoi(argv[2]);
50 int listen_sock=start(_port,_ip);//create socket
51 int newsock=-1;
52 int max_fd=0;
53 fd_set _reads;//many of read event
54 fd_set _writes;//many of write event
55 struct sockaddr_in client;
56 int fds_count=sizeof(fileds)/sizeof(fileds[0]);
57 socklen_t len=sizeof(client);
58 int i=0;
59 while(i<fds_count)
60 {
61 fileds[i]=-1; //init fileds[]
62 ++i;
63 }
64 fileds[0]=listen_sock;
65 max_fd=fileds[0];//init maxfd
66 int done=0;
67 while(!done)
68 {
69 FD_ZERO(&_reads); //每次循環進來都要進行初始化
70 FD_ZERO(&_writes);
71 FD_SET(listen_sock,&_reads);//set listen_sock to reads fd
72 struct timeval _timeout;
73 _timeout.tv_sec=20;
74 _timeout.tv_usec=0;
75 for(i=1;i<fds_count;++i)
76 {
77 if(fileds[i]>0)
78 {
79 FD_SET(fileds[i],&_reads);
80 if(fileds[i]>max_fd)
81 {
82 max_fd=fileds[i];
83 }
84 }
85 }
86 switch(select(max_fd+1,&_reads,NULL,NULL,&_timeout))
87 {//the return val is how many fd is ready
88 case 0: //timeout
89 printf("select is timeout\n");
90 break;
91 case -1://error
92 perror("select");
93 break;
94 default: //less than 1 fd is ready
95 {
96 for(i=0;i<fds_count;++i)
97 {
98 if(fileds[i]==listen_sock \
99 && FD_ISSET(fileds[i],&_reads))
100 {//listen_sock is ready
101 newsock=accept(listen_sock,(struct sockaddr*)&client ,&(len));
102 if(newsock<0)
103 {
104 perror("accept");
105 return 1;
106 }
107 printf("get a new connect... [fd:%d],[ip:%s]\n",news ock,inet_ntoa(client.sin_addr));
108 for(i=0;i<fds_count;++i)
109 {
110 if(fileds[i]==-1)
111 {
112 fileds[i]=newsock;//add newsock fd
113 break;
114 }
115 }
116 if(i==fds_count)//sum fd effective is full
117 {
118 close(newsock);
119 }
120 //break;
121 }else if(fileds[i]>0 &&FD_ISSET(fileds[i],&_reads))
122 {
123 char buf[1024];
124 ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
124 ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
125 if(_size>0)
126 {
127 buf[_size]='\0';
128 printf("client#%s",buf);
129 write(fileds[i],buf,_size);
130 }else if(_size==0)//client close
131 {
132 printf("client is closed...\n");
133 close(fileds[i]);
134 fileds[i]=-1;//set -1,
135 }
136 }
137 }
138 }
139 break;
140
141 }
142 }
143 return 0;
144 }客戶端:
1 #include<stdio.h>
2 #include<string.h>
3 #include<errno.h>
4 #include<stdlib.h>
5 #include<netinet/in.h>
6 #include<unistd.h>
7 #include<arpa/inet.h>
8
9 void Usage(const char*proc)
10 {
11 printf("Usage:%s [remoteip] [remoteport]\n",proc);
12 }
13
14 int main(int argc,char* argv[])
15 {
16 if(argc!=3)
17 {
18 Usage(argv[0]);
19 exit(1);
20 }
21
22 int _port=atoi(argv[2]);
23 char *_ip=argv[1];
1 #include<stdio.h>
2 #include<string.h>
3 #include<errno.h>
4 #include<stdlib.h>
5 #include<netinet/in.h>
6 #include<unistd.h>
7 #include<arpa/inet.h>
8
9 void Usage(const char*proc)
10 {
11 printf("Usage:%s [remoteip] [remoteport]\n",proc);
12 }
13
14 int main(int argc,char* argv[])
15 {
16 if(argc!=3)
17 {
18 Usage(argv[0]);
19 exit(1);
20 }
21
22 int _port=atoi(argv[2]);
23 char *_ip=argv[1];
24 int sock=socket(AF_INET,SOCK_STREAM,0);
25 if(sock<0)
26 {
27 perror("socket");
28 exit(2);
29 }
30 struct sockaddr_in remote;
31 remote.sin_family=AF_INET;
32 remote.sin_port=htons(_port);
33 remote.sin_addr.s_addr=inet_addr(_ip);
34 int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));
35 if(ret<0)
36 {
37 perror("connect");
38 exit(3);
39 }
40 char buf[1024];
41 while(1)
42 {
43 memset(buf,'\0',sizeof(buf));
44 printf("please input:");
45 fflush(stdout);
46 if(read(0,buf,sizeof(buf)-1)>0)
47 {
48 write(sock,buf,strlen(buf));
49 }
50
51 ssize_t _size=read(sock,buf,sizeof(buf)-1);
52 if(_size>0)
53 {
54 printf("server----client:%s",buf);
55 }
56
57 }
58 return 0;
59 }
結果回顯:

使用select實現多路復用同時也存在弊端:
每次調用select,都需要把fd集合從用戶態拷貝到內核態,需要在內核中遍歷傳遞進的所有文件描述符,當fd很多時導致開銷大
新聞名稱:用select實現IO的復用
文章出自:http://www.yijiale78.com/article32/pehcpc.html
成都網站建設公司_創新互聯,為您提供、App設計、網站維護、標簽優化、定制網站、網站排名
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯