I/O多路转接 ---- poll
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I/O多路转接 ---- poll相关的知识,希望对你有一定的参考价值。
一、poll
poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。
二、poll相关函数
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//fds: pollfd结构体
events: 要监视的事件
revents: 已经发生的事件, 设置标志 来反映相关条件的存在
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
// 只能作为描述字的返回结果存储在revents中
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
struct pollfd { int fd; /* 文件描述符 */ short events; /* 请求的事件 */ short revents; /* 返回的事件 */ };
//nfds: 要监视的描述符的数目
//timeout:指定poll在返回前没有接收事件时应该等待的时间【单位:ms】。
INFTIM: 永不超时
0 :立即返回
>0: 等待指定的时间
2、特点:
pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。
和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
三、poll 服务器
#include <stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> #include<unistd.h> #include<string.h> #include<errno.h> #include<sys/select.h> #include<sys/poll.h> #define _BACKLOG_ 5 #define _MAX_NUM_ 64 void usage(const char *proc) { printf("Usage: %s [ip][port]\n",proc); } static int startup(const char *ip,const int port) { int sock=socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket"); exit(1); } int opt=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(port); local.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0) { perror("bind"); exit(2); } if(listen(sock,_BACKLOG_) < 0) { perror("listen"); exit(3); } return sock; } static int poll_server(int listen_sock) { struct sockaddr_in client; socklen_t len=sizeof(client); struct pollfd fds[_MAX_NUM_]; fds[0].fd=listen_sock; fds[0].events=POLLIN; fds[0].revents=0; size_t i=0; for(;i<_MAX_NUM_;++i) { fds[i].fd=-1; fds[i].events=0; fds[i].revents=0; } int max_fd=1; int timeout=5000; while(1) { switch(poll(fds,max_fd,timeout)) { case -1://error perror("poll"); break; case 0://timeout printf("poll timeout"); break; default://normal { for(i=0;i<_MAX_NUM_;++i) { //is listen events ready? if(fds[i].fd == listen_sock && fds[i].revents == POLLIN) { int accept_sock=accept(listen_sock,(struct sockaddr*)&client,&len); if(accept_sock < 0) { perror("accept"); continue; } printf("get a client...[ip: %s][port: %d]\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port)); for(i=0;i<_MAX_NUM_;++i) { if(fds[i].fd == -1) { fds[i].fd=accept_sock; fds[i].events=POLLIN; max_fd++; break; } } if(i == _MAX_NUM_) { close(accept_sock); } } else if(fds[i].fd > 0 && fds[i].revents == POLLIN) { char buf[1024]; ssize_t _size=read(fds[i].fd,buf,sizeof(buf)-1); if(_size > 0)//read success { buf[_size]=‘\0‘; printf("Client # %s",buf); } else if(_size == 0)//client close { printf("clint close...\n"); struct pollfd tmp=fds[i]; fds[i]=fds[max_fd-1]; close(fds[max_fd-1].fd); fds[max_fd-1].fd=-1; fds[max_fd-1].events=0; fds[max_fd-1].revents=0; --max_fd; } } else {} } } break; } } return 0; } int main(int argc,char *argv[]) { if(argc != 3) { usage(argv[0]); return 1; } char *ip=argv[1]; int port=atoi(argv[2]); int listen_sock=startup(ip,port); poll_server(listen_sock); close(listen_sock); return 0; }
总结:
poll在返回后,需要通过遍历文件描述符来获取已经就绪的socket从而进行下一步操作;而且使用完监听套接字后,都需要进行关闭。
本文出自 “花开彼岸” 博客,请务必保留此出处http://zxtong.blog.51cto.com/10697148/1785978
以上是关于I/O多路转接 ---- poll的主要内容,如果未能解决你的问题,请参考以下文章