poll系统调用与select相似
select详解见博客:https://blog.csdn.net/smx_dd/article/details/85052852
也是在指定时间内轮询一定数量的文件描述符,来测试其中是否有就绪者。
poll原型:
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
fds:是一个pollfd结构类型的数组,它指定我们感兴趣的文件描述符上发生的可读、可写、异常事件。
pollfd结构体定义如下:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
pollfd结构包含3个部分:fd为文件描述符、events为监听的事件集合、revents为返回的事件集合
events和revents取值:
nfds:指定被监听的fds事件集合大小
nfds_t定义如下:
typedef unsigned long int nfds_t;
timeout:超时时间,和select类似,单位为毫秒。
返回值:返回值小于0说明出错,等于0说明超时,大于0表示poll由于监听描述符就绪而返回。
在网络编程中,socket可读就绪情况如下:
1.客户端连接到来,监听socket可读。
2.客户端数据到来,客户端socket可读。
poll系统调用优点:
1.pollfd结构包含了要监视的event和发⽣的event,不再使⽤select“参数-值”传递的⽅式. 接⼝使⽤⽐select更⽅便.
2.poll并没有最⼤数量限制 (但是数量过⼤后性能也是会下降).
缺点:
1.和select一样,需要轮询pollfd来获取就绪描述符。
2.每次调⽤poll都需要把⼤量的pollfd结构从⽤户态拷⻉到内核中.
使用poll函数实现tcp服务器,打破传统单线程不能处理多个客户端请求:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<poll.h>
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("Usage: ./name port!\n");
}
int i,j;
struct sockaddr_in server_addr;
socklen_t len=sizeof(server_addr);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(atoi(argv[1]));
server_addr.sin_addr.s_addr=INADDR_ANY;
int listen_fd=socket(AF_INET,SOCK_STREAM,0);
if(listen_fd<0)
{
perror("create socket error!");
return 1;
}
int ret=bind(listen_fd,(struct sockaddr*)&server_addr,len);
if(ret<0)
{
perror("bind error!");
return 1;
}
ret=listen(listen_fd,5);
if(listen_fd<0)
{
perror("listen error!");
return 1;
}
struct pollfd fd_list[1024];
for(i=0;i<1024;i++)
{
fd_list[i].fd=-1;
fd_list[i].events=0;
fd_list[i].revents=0;
}
for(i=0;i<1024;i++)
{
if(fd_list[i].fd==-1)
{
fd_list[i].fd=listen_fd;
fd_list[i].events=POLLIN;
break;
}
}
while(1)
{
ret=poll(fd_list,1024,2000);
if(ret<0)
{
perror("poll error!");
continue;
}
else if(ret==0)
{
printf("time out!\n");
continue;
}
for(i=0;i<1024;i++)
{
if(fd_list[i].fd==-1)
{
continue;
}
if(fd_list[i].revents!=POLLIN)
{
continue;
}
if(fd_list[i].fd==listen_fd)
{
struct sockaddr_in client_addr;
int new_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&len);
if(new_fd<0)
{
perror("accept error!");
continue;
}
printf("a new client connected!");
for(j=0;j<1024;j++)
{
if(fd_list[j].fd==-1)
{
fd_list[j].fd=new_fd;
fd_list[j].events=POLLIN;
break;
}
}
}
else
{
char buff[1024]={0};
int rlen=recv(fd_list[i].fd,buff,1023,0);
if(rlen<0)
{
perror("recv error!");
continue;
}
else if(rlen==0)
{
printf("client close!\n");
close(fd_list[i].fd);
fd_list[i].fd=-1;
continue;
}
printf("client: %s\n",buff);
}
}
}
close(listen_fd);
return 0;
}