poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪这
poll的原型:
#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
fds参数是一个pollfd结构类型的数组它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件,定义如下:
struct pollfd
{
int fd; //用户关注的文件描述符
short events; //注册的事件
short revents; //实际发生的事件,由内核填充
}
nfds:数组的长度、元素的个数,用户关注的文件描述符的个数
timeout:超时时间
返回值:-1 出错
0 超时
>0 就绪文件描述符的个数
与select相比:
1.用户关注的事件类型更多
2.内核修改的和用户关注的事件分开表示,每次调用不需要重新设置
3.文件描述符不再是按位表示,直接用int类型
3.1用户关注的文件描述符的值可以更大
3.2用户关注的文件描述符的个数由用户数组决定,所以个数会更多。
poll返回时,也是将用户关注的所有文件描述符返回。
poll检测就绪文件描述符的时间复杂度O(n),poll返回后,用户程序依旧需要循环检测哪些文件描述符就绪。
#define _GNU_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<poll.h>
#define SIZE 100//数组最大的长度
void init_fds(struct pollfd * fds)
{
int i = 0;
for(;i < SIZE;++i)
{
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
}
}
void inster_fds(struct pollfd * fds,int fd,short event)
{
int i = 0;
for(;i < SIZE ; ++i)
{
if(fds[i].fd = -1)
{
fds[i].fd = fd;//将文件描述符插入到数组里
fds[i].events = event;//将事件插入到数组里
break;
}
}
}
void delete_fd(struct pollfd * fds,int fd)
{
int i = 0;
for(; i < SIZE;++i)
{
if(fds[i].fd == fd)
{
fds[i].fd = -1;
fds[i].events = 0;
break;
}
}
}
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in caddr,saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
assert(res != -1);
listen(sockfd ,5);
struct pollfd fds[SIZE];//定义数组
init_fds(fds);//初始化数组
inster_fds(fds,sockfd,POLLIN);//先将链接文件描述符插入数组里,只有读事件,所以选择POLLIN事件
while(1)
{
int n = poll(fds,SIZE,-1);//
if(n <= 0)
{
printf("poll error\n");
continue;
}
//n>0,说明有文件描述符就绪,进行处理
//将整个数组遍历一遍,检查哪个文件描述符就绪
int i = 0;
for(; i < SIZE ;++i)
{
if(fds[i].fd != -1)//fd != -1 才能进行判断l
{
int fd = fds[i].fd;
if(fds[i].revents & POLLRDHUP)//如果有关闭TCP链接的事件发生,进行断开链接处理
{
close(fd);
delete_fd(fds,fd);
}
else if(fds[i].revents & POLLIN)//检查是否有读事件就绪
{
if(fd == sockfd)//代表有客户端链接事件发生
{
int len = sizeof(caddr);
int c = accept(fd,(struct sockaddr *) &caddr ,&len);
if(c < 0)//出错处理
{
continue;
}
inster_fds(fds,c,POLLIN|POLLRDHUP);//将用户的链接套接字添加进数组里
}
else//代表客户端发送事件发生,进行接收数据处理
{
char buff [128] = {0};
recv(fd,buff,127,0);
printf("%d : %s",fd,buff);
send(fd,"ok",2,0);
}
}
}
}
}
}