poll模型
poll模型和select模型差不多,都是通过轮询的方式监听,但是其缺点较多
struct pollfd
{
int fd; //指定要监听的文件描述符
short events; //指定监听fd上的什么事件
short revents; //fd上事件就绪后,用于保存实际发生的事件
};
服务器代码
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<ctype.h>
5 #include<sys/types.h>
6 #include<sys/socket.h>
7 #include<strings.h>
8 #include<errno.h>
9 #include<arpa/inet.h>
10 #include<poll.h>
11 #define DEFPORT 8000
12 int main(void)
13 {
14 int sfd,cfd;//server文件描述符 client文件描述符
15 int i,j,nReady,len,datalen;
16 char buf[1024];//数据
17 bzero(buf,sizeof(buf));
18 //网络初始化
19 struct sockaddr_in server_sock,client_sock;
20 bzero(&server_sock,sizeof(server_sock));
21 server_sock.sin_family = AF_INET;
22 server_sock.sin_port = htons(DEFPORT);
23 server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
24 sfd = socket(AF_INET,SOCK_STREAM,0);
25 bind(sfd,(struct sockaddr*)&server_sock,sizeof(server_sock));
26 listen(sfd,128);
27 //poll模型初始化
28 struct pollfd set[4096];
29 set[0].fd = sfd;
30 set[0].events = POLLIN;
31 for(i=1;i<4096;i++)
32 set[i].fd = -1;
33 while(1)
34 {
35 nReady = poll(set,4096,-1);//监听集合 最大监听数 阻塞监听 返回监听到
的数量
36 while(nReady)//循环,每次处理一个监听事件
37 {
38 if(set[0].revents==POLLIN)//判断是否是server读事件
39 {
40 len = sizeof(client_sock);
41 cfd = accept(sfd,(struct sockaddr*)&client_sock,&len);//连接
42 for(i = 1; i < 4096; i++)//将cfd存入监听集合,并设置监听事件
43 if(set[i].fd == -1)
44 {
45 set[i].fd = cfd;
46 set[i].events = POLLIN;
47 break;
48 }
49 if(i==1024)
50 perror("client too much\n");
51 set[0].revents = 0;//server读事件结束后不再监听
52 }
53 else
54 {
55 for(i = 1; i < 4096; i++)//找到对因的recv读事件
56 {
57 if(set[i].fd != -1)
58 {
59 if(set[i].revents == POLLIN)
60 {
61 if((datalen = recv(set[i].fd,buf,sizeof(buf),0)> 0))
62 {
63 printf("size:%d\n",datalen);
64 for(j = 0; j < datalen; j++)
65 buf[j] = toupper(buf[j]);
66 send(set[i].fd,buf,len,0);
67 bzero(buf,sizeof(buf));
68 }
69 if(len==0)
70 {
71 set[i].revents = 0;
72 close(set[i].fd);
73 set[i].fd = -1;
74 }
75 set[i].revents = 0;//处理完当前事件后不再处理
76 break;
77 }
78 }
79 }
80 }
81 --nReady;
82 }
83 }
84 return 0;
85 }
优点
1.不再像select一样需要将传入和传出集合分离,而是通过revent设置
2.可以监听事件的种类更加丰富,例如POLLRDNORM(数据可读)
、POLLERR(发生错误)、POLLHUP (发生挂起)等等
3.监听数量突破1024。
缺点
poll继承了select的几乎所有缺点
1.当轮询数量的增长,轮询监听导致IO处理效率较慢
2.用户必须自己去查找是哪个事件就绪,浪费时间
3.存在大量的无意义的拷贝,浪费资源
4.没有兼容性,无法在windows下使用
5.timeout只能设置到毫秒级别,而select可以达到微秒。
总结
对于第三个优点,poll模型确实可以比select模型监听更多的事件,但是并没有解决实质性的问题。因为在select模型中,1024这个值是因为采用fd_set这个类型导致的,而之所以选择这个类型是因为在监听过程中,select将监听集合中的监听项加入到内核中的IO设备等待队列中,而这个队列采用的是轮询监听的方式,而轮询监听带来的最大问题就是不能及时的处理新的事件请求,必须处理完上一轮所有事件之后,才会处理下一轮的事件,当访问较为频繁时,会出现问题。所以,研究者通过实验,最终确定1024为最优值。因此在poll模型中,单纯的去突破1024并没有什么意义,无法解决问题。