重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
一、poll
创新互联建站专注于网站建设|成都网站改版|优化|托管以及网络推广,积累了大量的网站设计与制作经验,为许多企业提供了网站定制设计服务,案例作品覆盖湿喷机等行业。能根据企业所处的行业与销售的产品,结合品牌形象的塑造,量身设计品质网站。
poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。
二、poll相关函数
#include
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#include #include #include #include #include #include #include #include #include #include #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从而进行下一步操作;而且使用完监听套接字后,都需要进行关闭。