poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。
#include <poll.h>
int poll(struct pollfd fd[], nfds_t nfds, int timeout);
poll与select不同,select用三个文件描述符集,pollfd结构包含了要监视的event和发⽣生的event,不再使⽤用select“参数-值”传递的⽅方式。同时,pollfd并没有最⼤大数量限制(但是数量过⼤大后性能也是会下降)。 和select函数⼀一样,poll返回后,需要轮询pollfd数组来获取就绪的描述符。poll将返回的事件放在结构体的revents中。
简单的poll服务器:
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
void usage(const char* proc)
{
printf("usage: %s [local_ip] [port]\n",proc);
}
int startup(const char* ip,int port)
{
//pfd.fd = client_sock;
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
exit(1);
}
struct sockaddr_in sd;
sd.sin_family = AF_INET;
sd.sin_port = htons(port);
sd.sin_addr.s_addr = inet_addr(ip);
//int socks;
if(bind(sock,(struct sockaddr*)&sd,sizeof(sd)) < 0)
{
perror("bind");
exit(2);
}
if(listen(sock,5) < 0)
{
perror("listen");
exit(3);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc != 3)
{
usage(argv[0]);
exit(0);
}
struct pollfd pfd[100];
int i = 0;
int max = 0;
for(;i<100; i++)
{
pfd[i].fd = -1;
}
int client_sock = startup(argv[1],atoi(argv[2]));
while(1)
{
pfd[0].fd = client_sock;
pfd[0].events = POLLIN;
max++;
int x = poll(pfd,max,-1);
if(x > 0)
{
i=0;
if(((pfd[0].revents & pfd[0].events) == 1) && pfd[0].fd == client_sock)
{
struct sockaddr_in peer;
socklen_t len =sizeof(peer);
int client = accept(client_sock,(struct sockaddr*)&peer,&len);
printf("get a new client\n");
for(;i<100;i++)
{
if(pfd[i].fd < 0)
{
pfd[i].fd = client;
pfd[i].events = POLLIN;
break;
}
}
}
for(i=1;i<max;i++)
{
if((pfd[i].revents & pfd[i].events) == 1)
{
//printf("a\n");
char buf[1024];
int new_fd = pfd[i].fd;
int s;
s = read(new_fd,buf,sizeof(buf));
if(s < 0)
{
printf("client exit!\n");
close(new_fd);
}
buf[s]=0;
printf("client : %s\n",buf);
}
}//for
}//
else
{
perror("poll");
exit(6);
}
}
return 0;
}
poll的优点:
1)poll() 不要求开发者计算最大文件描述符加一的大小。
2)poll() 在应付大数目的文件描述符的时候相比于select速度更快
3)它没有最大连接数的限制,原因是它是基于链表来存储的。
poll的缺点:
1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符。