一,IO复用的方法
IO复用的方法:select poll epoll
IO复用的功能
这里的描述符就是套接字
以前TCP服务器端和客户端 一个服务器端要连接10个客户端就需要创建10个线程 学校发书,所有人在图书馆排队领书没到你你就在等相当于阻塞,另一种到你了我给你打电话你再来领就不会出现阻塞(例子) 在程序中来讲就是我们将所有要关注的描述符全部注册到select上,select帮我们检测哪个描述符上有数据产生(有可能是一个或2,3个上同时有数据)
举个例子来使用select
检测键盘(键盘也是描述符),如果5秒内键盘上有数据的输入,我们就把数据读一下并打印出来,如果5秒内没有数据我们就打印个time out
select在Linux上和Windows都有
二,一个描述符的select代码
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<sys/select.h>
6
7 #define STDIN 0
8 int main()
9 {
10 int fd=STDIN;
11 fd_set fdset;
12 while(1)
13 {
14 FD_ZERO(&fdset);
15 FD_SET(fd,&fdset);
16 struct timeval tv={5,0};如果没有输入数据或者还没有到5秒就会在这里阻塞住
17 int n=select(fd+1,&fdset,NULL,NULL,&tv);
18 if(n<0)
19 {
20 printf("select err\n");
21 }
22 else if(n==0)
23 {
24 printf("time out\n");
25 }
26 else
27 {
28 if(FD_ISSET(fd,&fdset))
29 {
30 char buff[128]={0};
31 read(fd,buff,128);
32 printf("read:%s\n",buff);
33 }
34 }
35 }
36 }
三,多描述符的代码
将select用到tcp的服务器端 fd是文件描述符 阻塞 如果描述符是sockfd则调用accept()接受连接 memset(&saddr,0,sizeof(saddr));
封装的fds_init(); fds_add(); fds_del();都是用来对数组进行操作的
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<string.h>
5 #include<sys/select.h>
6 #include<sys/socket.h>
7 #include<arpa/inet.h>
8 #include<netinet/in.h>
9 #include<assert.h>
10
11 #define MAX 10
12
13
14 void fds_init(int fds[])
15 {
16 int i=0;
17 for(;i<MAX;i++)
18 {
19 fds[i]=-1;
20 }
21 }
22
23 void fds_add(int fd,int fds[])
24 {
25 if(fd<0)
26 {
27 return;
28 }
29 for(int i=0;i<MAX;i++)
30 {
31 if(fds[i]==-1)
32 {
33 fds[i]=fd;
34 break;
35 }
36 }
37 }
38
39 void fds_del(int fd,int fds[])
40 {
41 for(int i=0;i<MAX;i++)
42 {
43 if(fds[i]==fd)
44 {
45 fds[i]=-1;
46 break;
47 }
48 }
49 }
50 int socket_init();
51 int main()
52 {
53 int sockfd=socket_init();
54 assert(sockfd!=-1);
55
56 int fds[MAX];
57 fds_init(fds);
58 fds_add(sockfd,fds);
59 fd_set fdset;
60 while(1)
61 {
62 FD_ZERO(&fdset);
63 int maxfd=-1;
64 for(int i=0;i<MAX;i++)
65 {
66 if(fds[i]=-1)
67 {
68 continue;
69 }
70
71 FD_SET(fds[i],&fdset);
72 if(maxfd<fds[i])
73 {
74 maxfd=fds[i];
75 }
76 }
77
78 struct timeval tv={5,0};
79 int n=select(maxfd+1,&fdset,NULL,NULL,&tv);
80 if(n<0)
81 {
82 printf("select err\n");
83 }
84 else if(n==0)
85 {
86 printf("time out\n");
87 }
88 else
89 {
90 for(int i=0;i<MAX;i++)
91 {
92 if(fds[i]==-1)
93 {
94 continue;
95 }
96
97 if(FD_ISSET(fds[i],&fdset))
98 {
99 if(fds[i]==sockfd)
100 {
101 struct sockaddr_in caddr;
102 int len=sizeof(caddr);
103 int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
104 if(c<0)
105 {
106 continue;
107 }
108 printf("accept c=%d\n",c);
109 fds_add(c,fds);
110 }
111 else
112 {
113 char buff[128]={0};
114 int num=recv(fds[i],buff,127,0);
115 if(num<=0)
116 {
117 printf("client close\n");
118 close(fds[i]);
119 fds_del(fds[i],fds);
120 }
121 else
122 {
123 printf("recv(%d)=%s\n",fds[i],buff);
124 send(fds[i],"ok",2,0);
125 }
126 }
127 }
128 }
129 }
130 }
131 }
132
133 int socket_init()
134 {
135 int sockfd=socket(AF_INET,SOCK_STREAM,0);
136 if(sockfd==-1)
137 {
138 return -1;
139 }
140 struct sockaddr_in saddr;
141 memset(&saddr,0,sizeof(saddr));
142 saddr.sin_family=AF_INET;
143 saddr.sin_port=htons(6000);
144 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
145 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
146 if(res==-1)
147 {
148 return -1;
149 }
150 res=listen(sockfd,5);
151 if(res==-1)
152 {
153 return -1;
154 }
155
156 return sockfd;
157 }
客户端是TCP有循环代码
|