int poll(struct pollfd *fds, nfds_t nfds, int timeout);
函数说明:跟select类似,委托内核监控可读,可写,异常事件
函数参数:
fds:一个struct pollfd结构体数组的首地址
struct pollfd {
int fd; //要监控的文件描述符,fd=-1 内核不再监控
short events; //输入参数,告诉内核要监控的事件,读事件,写事件
short revents; //输出参数,内核告诉应用程序有哪些文件描述符有事件发生
};
event/revents:
POLLIN:可读事件
POLLOUT:可写事件
PLOOERR:异常事件
nfs:告诉内核监控的范围,具体是:数组下标的最大值+1
timeout:0:不阻塞,立刻返回
-1:表示一直阻塞,直到事件发生
>0:表示阻塞时长,在时长范围内若有事件发生会立刻返回;超过时长也会立刻返回
返回值:>0 发生变化的文件描述符个数
=0:没有文件描述符发生变化
-1:表示异常
使用poll模型开发服务端流程:
- 创建socket,得到监听文件描述符lfd–socket()
- 设置端口复用—setsockopt()
- 绑定bind–()
- 定义结构体数组
struct pollfd client[1024];
client[0].fd=lfd;
client[0].events=POLLIN;
int maxi=0;
for(i=1;i<1024;i++){
client[i].fd=-1;
}
k=0;
while(1){
nready=poll(client,maxi+1,-1);
//异常情况
if(nready<0){
if(erron==EINTR){//信号被中断
continue;
}
break;
}
//有客户端连接请求到来
if(client[0].revents==POLLIN&&client[0].fd==lfd){
k++;
//接收新的客户端连接
cfd==accept(lfd,NULL,NULL);
//寻找在client数组中可用位置
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;
}
//修改client数组下标最大值
if(maxi<i){
maxi=i;
}
if(--nready==0){
continue;
}
}
//下面是有客户端发生数据的情况
for(i=0;i<=maxi;i++){
sockfd=client[i].fd;
//如果client数组中fd为-1,表示已经不再让内核监控,已经close
if(client[i].fd==-1){
continue;
}
if(client[i].revents==POLLIN){
//read数据
n=read(sockfd,buf,sizeof(buf));
if(n<=0){
close(sockfd);
client[i].fd=-1;
continue;
}else{
//发生数据给客户端
write(sockfd,buf,n);
}
}
}
}
close(lfd);