poll使用一个结构体指针代替select中读事件、写事件及异常事件。
结构体组成:
events(请求事件)关心该文件描述符的什么事件
所关心的事件有:
poll函数原型:int poll(struct pollfd* fds,nfds_t nfds,int timeout)
fds:为一个struct pollfd结构体类型的数组,存放要检测其状态的socket描述符
nfds:表示结构体数组总大小
timeout:poll函数阻塞等待的时间
return val:
大于0:结构体数组中准备好读、写或出错状态的socket描述符的总数量;
等于0:结构体数组中没有任何socket描述符就绪,poll超时,超时时间是timeout毫秒
小于: poll函数调用失败
服务器端代码:(针对单客户端)
1 #include<stdio.h>
2 #include<string.h>
3 #include<sys/socket.h>
4 #include<sys/types.h>
5 #include<netinet/in.h>
6 #include<arpa/inet.h>
7 #include<errno.h>
8 #include<poll.h>
9 #include<stdlib.h>
10 #include<assert.h>
11
12 #define MAX_SIZE 64
13 #define BACK_LOG 5
14 void Usage(const char* proc)
15 {
16 printf("Usage:%s [ip] [port]\n",proc);
17 }
18
19 static int startup(char* ip,int port)
20 {
21 assert(ip);
22 int listen_sock=socket(AF_INET,SOCK_STREAM,0);
23 if(listen_sock<0)
24 {
25 perror("socket");
26 exit(1);
27 }
28 struct sockaddr_in local;
29 local.sin_family=AF_INET;
30 local.sin_port=htons(port);
31 local.sin_addr.s_addr=inet_addr(ip);
32 socklen_t size=sizeof(local);
33 if(bind(listen_sock,(struct sockaddr*)&local,size)<0)
34 {
35 perror("bind");
36 exit(2);
37 }
38 if(listen(listen_sock,BACK_LOG)<0)
39 {
40 perror("listen");
41 exit(3);
42 }
43 return listen_sock;
44 }
45 int main(int argc,char* argv[])
46 {
47 if(argc!=3)
48 {
49 Usage(argv[0]);
50 exit(1);
51 }
52 char *_ip=argv[1];
53 int _port=atoi(argv[2]);
54 int listen_sock=startup(_ip,_port);
55 struct sockaddr_in client;
56 socklen_t size=sizeof(client);
57 struct pollfd fd_set[MAX_SIZE];
58 fd_set[0].fd=listen_sock;
59 fd_set[0].events=POLLIN;
60 fd_set[0].revents=0;
61 char buf[1024];
62 int max_fd=0;
63 int timeout=5000;
64 int done=0;
65 int i=1;
66 int j=0;
67 for(;i<MAX_SIZE;++i)
68 {
69 fd_set[i].fd=-1;
70 }
71 while(!done)
72 {
73 timeout=5000;
74 switch(poll(fd_set,max_fd+1,timeout))
75 {
76 case -1:
77 perror("poll");
78 break;
79 case 0:
80 printf("poll timeout...\n");
81 break;
82 default:
83 {
84 for(i=0;i<MAX_SIZE;++i)
85 {
86 if(fd_set[i].fd==listen_sock && \
87 (fd_set[i].revents&POLLIN))
88 {//**判断是否为监听状态且判断它返回的哪一个就绪事件
89 int new_sock=accept(listen_sock,(struct sockaddr*)&client,&size);
90 if(new_sock<0)
91 {
92 perror("accept");
93 return -1;
94 }
95 printf("get a new conn... [fd:%d] [ip:%s]\n",\
96 new_sock,inet_ntoa(client.sin_addr));
97 for(j=0;i<MAX_SIZE;++j)
98 {
99 if(fd_set[j].fd==-1)
100 {
101 fd_set[j].fd=new_sock;
102 fd_set[j].events=POLLIN;
103 break;
104 }
105 }
106 if(j==MAX_SIZE)
107 {
108 printf("fd_set[] is full...\n ");
109 close(new_sock);
110 exit(1);
111 }
112 if(j>max_fd)
113 {
114 max_fd=j;
115 }
116
117 }else if(fd_set[i].fd>0 &&\
118 (fd_set[i].revents&POLLIN))
119 { //表示读事件是否已经就绪
120 ssize_t _size=read(fd_set[i].fd,buf,sizeof(buf)-1);
121 if(_size>0)
122 {
123 buf[_size]='\0';
124 printf("client:%s",buf);
125 fd_set[i]._events=POLLOUT;
126 fd_set[i].revents=0;
127 }
128 else if(_size==0)
129 {
130 printf("client is closed...\n");
131 close(fd_set[i].fd);
132 fd_set[i].fd=-1;
133 }
134 }else if(fd_set[i].fd>0 &&\
135 fd_set[i].revents&POLLOUT)
136 { //写事件就绪
137 int fd=fd_set[i].fd;
138 write(fd,buf,sizeof(buf)-1);
139 fd_set[i].events=POLLIN;
140 }
141 }
142 }
143 break;
144
144 }
145 }
146
147
148 return 0;
149 }
客户端代码:
1 #include<stdio.h>
2 #include<string.h>
3 #include<sys/socket.h>
4 #include<sys/types.h>
5 #include<netinet/in.h>
6 #include<arpa/inet.h>
7 #include<errno.h>
8 #include<stdlib.h>
9 #include<assert.h>
10
11 void Usage(const char* proc)
12 {
13 printf("Usage:%s [remoteip] [remotrport]\n",proc);
14 }
15
16 int main(int argc,char* argv[])
17 {
18 if(argc!=3)
19 {
20 Usage(argv[0]);
21 exit(1);
22 }
23 int sock=socket(AF_INET,SOCK_STREAM,0);
24 if(sock<0)
25 {
26 perror("sock");
27 exit(2);
28 }
29 char *_ip=argv[1];
30 int _port=atoi(argv[2]);
31 struct sockaddr_in remote;
32 remote.sin_family=AF_INET;
33 remote.sin_port=htons(_port);
34 remote.sin_addr.s_addr=inet_addr(_ip);
35 socklen_t len=sizeof(remote);
36 int ret=connect(sock,(struct sockaddr*)&remote,len);
37 if(ret<0)
38 {
39 perror("connect");
40 return -1;
41 }
42 char buf[1024];
43 while(1)
44 {
45 memset(buf,'\0',sizeof(buf));
46 printf("please input:");
47 fflush(stdout);
48 if(read(0,buf,sizeof(buf)-1)>0)
49 {
50 write(sock,buf,strlen(buf));
51 }
52
53 ssize_t _size=read(sock,buf,sizeof(buf)-1);
54 if(_size>0)
55 {
56 printf("server---client:%s",buf);
57 }
58 }
59 close(sock);
60 return 0;
61 }
运行结果:
总结:(select与poll之间的区别)
select:使用三个文件描述符集(分别为读事件、写事件、异常事件)表示它们各自关心什么事件,将对应的文件描述符设置进去
它存在一定的弊端:
1.每次轮询前都要对所关心的文件描述符集进行设置及初始化(因为它们是输入输出型参数),每次都要遍历所有的文件描述符
2.它依赖文件描述符,但是文件描述符集的大小是有一定的限度的,当有大量的客户端同时请求服务器时不适宜使用
3.它的三个文件描述符集当中若有多个被修改,每次修改都要从用户态切换到内核态,内核态来负责修改文件描述符的状态变化
poll:使用一个结构体数组来代替select中的三个文件描述符集,它的大小不受限制
优化:
1.若有需要关心的文件描述符时,将它保存到结构体中,并设置该描述符所关心的事件,每次轮询完后若有无效的文件描述符时,将其描述符的状态置-1,当再次调poll函数时会忽略它
2.当有新的文件描述符时,重新遍历结构体,将出现第一个为-1的状态时,将它设置为要关心的描述符事件状态,每次有新的文件描述符加入时,更改要关心的文件描述符数量
3.调用poll函数后,结构体中的revents(返回已经就绪的事件)会存储就绪事件状态,重新调用poll之前,系统设置该状态默认其为0,重新监听关心事件
但poll也有相应的弊端:当同一时刻有大量客户端发来请求连接,但有只有很少的事件处于就绪状态,因此可能随着监视描述符数量的增长,效率也会降低
转载于:https://blog.51cto.com/10541559/1783845