I/O多路复用—poll服务器
来源:互联网 发布:类似惠头条的软件 编辑:程序博客网 时间:2024/06/05 01:03
poll是I/O多路复用中的一种方式,select将三种事件进行了区分,并且用三个位图来表示不同的监测事件。而poll统一用一种结构来管理要监测的事件。
poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况,下面是pollfd的结构:
#include <poll.h>int poll(struct pollfd fds[], nfds_t nfds, int timeout);参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况,下面是pollfd的结构:
struct pollfd {int fd; /*文件描述符*/short events; /* 等待的需要测试事件 */short revents; /* 实际发生了的事件,也就是返回结果 */};
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
返回值:
>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
-1: poll函数调用失败,同时会自动设置全局变量errno;
>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
-1: poll函数调用失败,同时会自动设置全局变量errno;
poll支持的常见事件类型:
poll的简易服务器:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <poll.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#define POLLFD_SIZE 1024//一个 对文件描述符事件struct pollfd array_pollfd[POLLFD_SIZE];/* 结构体成员详情 struct pollfd { int fd; // 关心的描述符 short events; // 关心的事件 short revents; // 发生的事件 }; *//*获取一个监听的socket*/int get_listen(char *ip, short port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock <0) { perror("socket"); exit(2); } 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); //bind if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0) { perror("bind"); exit(3); } //listen if(listen(sock,10)<0) { perror("listen"); exit(4); } return sock;}/*运行poll_server服务器*/void poll_server(int listen_sock){ /*将负责的监听的sock注册*/ array_pollfd[0].fd = listen_sock; array_pollfd[0].events = POLLIN; int idx = 1; for(;idx < POLLFD_SIZE; ++idx) array_pollfd[idx].fd= -1; int timeout = 1000;/*1000毫秒*/ while(1) { int res = poll(array_pollfd,POLLFD_SIZE,timeout); if(res == 0) printf("timeout\n"); else if(res < 0) perror("poll"); else { //有关心的事件已就绪 int index = 0; for(;index < POLLFD_SIZE;++index) { if(index == 0 && array_pollfd[0].revents & POLLIN) { //listen_sock 读事件就绪,响应accpet struct sockaddr_in cliaddr; socklen_t len = sizeof(cliaddr); int new_sock = accept(listen_sock,(struct sockaddr*)&cliaddr,&len); if(new_sock < 0) { perror("accept"); continue; } else { printf("get a client:%s, %d\n",\ inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port)); //将新的sock添加到数组中 int k = 1; for(;k < POLLFD_SIZE;++k) { if(array_pollfd[k].fd < 0) { array_pollfd[k].fd = new_sock; //将新的sock关注读事件 array_pollfd[k].events = POLLIN; break; } } //表示没有可用的文件接口 if(k == POLLFD_SIZE) { close(new_sock); return ; } } } else if(index != 0 && array_pollfd[index].revents & POLLIN) { //其他文件描述符读事件就绪 char buf[1024]; memset(buf,0,1024); ssize_t s = read(array_pollfd[index].fd,buf,sizeof(buf)-1); if(s > 0) { buf[s] = 0; printf("client say#:%s\n",buf); array_pollfd[index].events = POLLOUT; } else if(s <= 0) { printf("client quit\n"); close(array_pollfd[index].fd); //必须修改文件描述符为初始状态, array_pollfd[index].fd = -1; } } else if(index != 0 && array_pollfd[index].revents & POLLOUT) { //其他文件描述符写事件就绪 const char* msg = "HTTP/1.1 200 OK\r\n\r\n<html><br/><h1>Hello poll!</h1></html>"; write(array_pollfd[index].fd,msg,strlen(msg)); close(array_pollfd[index].fd); array_pollfd[index].fd = -1; } } } }}int main(int argc, char* argv[]){ if(argc != 3) { printf("Usge:%s [ip] [port]\n",argv[0]); return 1; } int listen_sock = get_listen(argv[1],atoi(argv[2])); poll_server(listen_sock); return 0;}
阅读全文
0 0
- I/O多路复用—poll服务器
- I/O多路复用之poll服务器
- poll() | 多路复用 I/O
- poll() | 多路复用 I/O
- I/O多路复用poll
- I/O多路复用——poll
- I/O多路复用之poll
- I/O 多路复用之poll
- I/O多路复用之poll
- poll实现I/O多路复用
- poll实现I/O多路复用
- I/O多路复用之poll
- I/O多路复用之poll
- I/O多路复用之poll
- I/O多路复用之poll
- I/O多路复用——select函数与poll函数
- I/O 多路复用入门——select/poll/epoll
- I/O多路复用—select服务器
- 下拉菜单——css方式实现二级菜单
- jQuery:Installation, Overview, and Getting Started
- Assign Cookies
- angularjs api
- centos中Hadoop2.7.1 hbase1.3编译snappy
- I/O多路复用—poll服务器
- C#中实现label中文字循环滚动
- page fault带来的性能问题
- 数据库中char, varchar, nvarchar的差异
- 10分钟搞定linux编辑器vim的配置
- deviceDriver.py与robot framework结合使用的简单实例
- OpenGL 各类库的解析 gl/glu/glut/freeglut/glfw/glew
- 不同字体的绘制【OpenGL】【FreeType】
- 一款实用的android相册选择器,单选,双选