poll
- 跟select类似,也是委托内核监控文件描述符,可读可写、异常事件
函数原型
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
- fds:传入传出参数,是一个结构体数组
- fds.fd:要监控的文件描述符
- fds.events:输入参数,要监控的事件
- POLLIN:读事件
- POLLOUT:写事件
- POLLERR:异常事件
- fds.revents:输出参数,返回事件
- nfds:数组实际有效内容的个数,监控范围,具体是数组下标的最大值+1
- timeout:
- 0:不阻塞,立即返回
- -1:表示一直阻塞,直到有事件发生
- >0:表示阻塞的时长,在时长范围内有事件发生会立刻返回
- 返回值:
- >0发生变化的文件描述符个数
- =0,超时时长,无文件描述符变化
- -1,异常
服务器代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <errno.h>
#include "wrap.h"
#include <arpa/inet.h>
#include <ctype.h>
int main(void)
{
int lfd = socket(AF_INET,SOCK_STREAM,0);
int opt = 1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
struct sockaddr_in serv;
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
Bind(lfd,(struct sockaddr *)&serv,sizeof(serv));
Listen(lfd,128);
fd_set readfds;
fd_set tmpfds;
FD_ZERO(&readfds);
FD_ZERO(&tmpfds);
FD_SET(lfd,&readfds);
struct pollfd client[1024];
client[0].fd = lfd;
client[0].events = POLLIN;
int nready = 0;
int maxi = 0;
int i = 0;
int cfd = 0;
int nbuf = 0;
char buf[1027] = "";
for(i = 1;i<1024;i++)
{
client[i].fd = -1;
}
maxi = lfd;
while(1)
{
nready = poll(client,maxi+1,-1);
if(nready<0)
{
if(errno==EINTR)
{
continue;
}
break;
}
if(client[0].revents==POLLIN)
{
cfd = Accept(lfd,NULL,NULL);
for(i = 0;i<1024;i++)
{
if(client[i].fd == -1)
{
client[i].fd = cfd;
client[i].events = POLLIN;
break;
}
}
if(i==1024)
{
close(cfd);
continue;
}
if(maxi<i)
{
maxi = i+1;
}
}
if(nready==0)
{
continue;
}
for(i=1;i<maxi+1;i++)
{
if(client[i].fd==-1)
{
continue;
}
if(client[i].revents==POLLIN)
{
nbuf = Read(client[i].fd,buf,sizeof(buf));
if(nbuf<=0)
{
close(client[i].fd);
client[i].fd = -1;
if(i==maxi-1)
{
maxi--;
}
}
else
{
Write(client[i].fd,buf,nbuf);
}
}
}
}
close(lfd);
return 0;
}
总结
- 通过数组监控文件描述符,如果fd为-1就不监控
- 通过传出参数去得到事件