Linux网络编程---I/O复用模型之poll
来源:互联网 发布:递推算法求韩信点兵 编辑:程序博客网 时间:2024/04/30 08:41
Linux网络编程—I/O复用模型之poll
1.函数poll
poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。
#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);//返回值:若成功,返回就绪的描述符个数,若超时则为0,若出错则为-1
- fds是指向一个pollfd结构第一个元素的指针。每一个元素都是pollfd结构类型,用于测试某个给定描述符fd的条件
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */};
要测试的条件在events中指定,函数相应的revents成员返回该描述符的状态,一个为调用值,一个为返回结果,这与select的传入传出参数不同。
events和revents可以设置以下常量的一个或多个的按位或结果:
POLLIN //普通或带外优先数据可读,即POLLRDNORM | POLLRDBANDPOLLRDNORM //数据可读POLLRDBAND //优先级带数据可读POLLPRI //高优先级可读数据POLLOUT //普通或带外数据可写POLLWRNORM //数据可写POLLWRBAND //优先级带数据可写//下面三个revents不包含POLLERR //发生错误POLLHUP //发生挂起POLLNVAL //描述字不是一个打开的文件
- timeout指定poll函数返回前等待多长时间,它是一个指定应等待毫秒数的正值。
|timeout值|说明|
|:-:|:-:|
|-1|永远等待|
|0|立即返回,不阻塞进程|
|>0|等待指定数目的毫秒数|
- nfds 是监控数组中有多少文件描述符需要被监控
如果我们不关心某个特定的描述符,那么可以把与它对应的pollfd结构的fd成员设置为一个负值。poll函数会忽略这样的pollfd结构的events成员,返回时将其revents成员的值置为0。
select模型最多可以创建一个1024个文件描述符大小的集合,这是因为受到fd_set的固定数据类型的限制,而poll则没有这样的问题,因为分配一个pollfd结构的数组并把数组中的元素通知内核称为调用者的责任。但是poll模型任然使用的是轮询模型,效率比较低下。
2. poll模型实现
2.1 服务器端
#include "wrap.h"#include <poll.h>#include <limits.h>#include <sys/stropts.h>#define MAXLINE 1024#define INFTIM -1#define OPEN_MAX 3000int main(int argc, char *argv[]){ int i, maxi, listenfd, connfd, sockfd; int nready; ssize_t n; char buf[MAXLINE]; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in clientaddr; listenfd = start_ser(argv[1], argv[2]);//监听文件描述符 client[0].fd = listenfd;//将监听文件描述符加入pollfd数组中 client[0].events = POLLIN;//设置为输入可读 for(i = 1; i < OPEN_MAX; i++){//初始化结构体数组 client[i].fd = -1; } maxi = 0; while(1){ nready = poll(client, maxi+1, INFTIM); //阻塞等待注册时间发生 if(client[0].revents & POLLIN){//当监听文件描述符响应有新连接请求 clilen = sizeof(clientaddr); connfd = Accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);//接受新客户 for(i = 1; i < OPEN_MAX; i++){ if(client[i].fd < 0){ client[i].fd = connfd; //把新客户的文件描述符加入数组 break; } } if(i == OPEN_MAX){ //连接新客户上限 Close(connfd); perr_exit("too many clients"); } client[i].events = POLLIN; //新客户端的处理事件 if(i > maxi){ maxi = i; //更新最大值 } if(--nready == 0){ //没有可读的描述符跳过本次循环 continue; } } for(i = 1; i <= maxi; i++){ //请求所有客户端的数据 if((sockfd = client[i].fd) < 0){ continue; } if(client[i].revents & POLLIN){ //POLLIN事件发生 memset(buf, '\0', MAXLINE); if((n = Read(sockfd, buf, MAXLINE-1)) < 0){ if(errno == ECONNRESET){ //当客户端发送reset Close(sockfd); client[i].fd = -1; }else{ perr_exit("read err"); } }else if(n == 0){ Close(sockfd); client[i].fd = -1; }else{ printf("client : %s\n", buf); } if(--nready == 0){ //没有可读的描述符跳过本次循环 break; } } } } Close(connfd); Close(listenfd); return 0;}
2.2客户端
#include "wrap.h"int main(int argc, char *argv[]){ struct sockaddr_in serveraddr; int connfd; connfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET, argv[1], &serveraddr.sin_addr); Connect(connfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); char buf[1024]; while((fgets(buf, 1024, stdin)) != NULL){ Write(connfd, buf, strlen(buf)); } Close(connfd); return 0;}
2.3程序测试结果
0 0
- Linux网络编程---I/O复用模型之poll
- linux编程---网络编程之复用I/O模型
- Linux网络编程---I/O复用模型之select
- Linux网络编程---I/O复用模型之epoll
- I/O复用模型之poll
- I/O复用之poll模型
- Linux网络编程——I/O复用之poll函数
- Linux网络编程15——I/O复用之poll详解
- Linux网络编程——I/O复用之poll函数
- Linux网络编程【七】:TCP协议高性能服务器(http)模型之I/O多路转接poll
- 网络编程之I/O复用模型select
- linux网络编程十六:I/O复用的应用-poll简单实现聊天室程序
- Poll() I/O复用模型
- linux 网络编程 I/O复用 select,poll ,epoll
- Linux【网络编程】——I/O多路转接之Poll服务器
- LINUX系统I/O复用技术之二:poll()
- 网络I/O模型select/poll/epoll
- Linux网络编程之I/O复用循环服务器
- android系统级别硬件访问服务程序
- 二叉树的高度 java 利用递归和层次遍历两种方法
- 【集合框架】4. Set容器
- 一元多项式的加减
- mysql 常用命令
- Linux网络编程---I/O复用模型之poll
- 【集合框架】5. Collections类
- android 开发 -- NavigationView和DrawerLayout实现 侧滑栏(Material Design)
- 时间序列分析这件小事(六)--非平稳时间序列与差分
- 基于JQuery 的分页控件
- java调用spark的借口运行WordCount
- 面向切面编程AOP实战
- 【集合框架】6. 迭代模式
- [读书笔记]程序员的自我修养 chp10