网络编程学习_IO复用:select/poll
来源:互联网 发布:怎么看见手机淘宝评价 编辑:程序博客网 时间:2024/05/21 10:00
本文为UNP第6章学习笔记
一, select函数
#include <sys/select.h>
int select(int maxfd,fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout);
参数:
- maxfd: select管理的最大fd+1, 也就是说你必须自己算出最大的fd是多大
- readset: 需要监控可读的fd集合, 只要read/accept操作不会阻塞,就算可读状态, 包括对方已关闭(返回0),套接字出错(返回负值),可读(返回正值),有新连接(可accept)
- writeset 需要监控可写的fd集合,wrte操作不阻塞或非阻塞socket中connect已完成,就算可写, 包括对方已关闭(SIGPIPE信号),套接字出错(返回负值),可写, connect完成或出错
- exceptset 异常条件的fd集合,通常用不到, 注意socket出错不算异常,而算是可读或可写
- timeout: NULL:阻塞 为0的timeval: 立刻返回 非0的timeval: 带定时器的阻塞
返回值:
- >0: 就绪fd的数目
- =0:超时
- <0:出错
二, fd_set相关宏
fd_set用来表示一组fd集合, 一般是一个long int数组,可能的实现如下:
struct fd_set{
long int fd_bits[16];
};
fd_set用每个位是1/0来记录fd, 16个long int共有 16*64=1024位, 因此select只能处理最多1024个fd.
fd_set可能有不同的实现,但我们只需要关注这4个操作fd_set的宏:
void FD_ZERO(fd_set* fdset);//将整个fdset置0
void FD_SET(int fd,fd_set* fdset);//将某个fd加到fdset中
void FD_CLR(int fd,fd_set* fdset);//将某个fd从fdset中删除
int FD_ISSET(int fd,fd_set* fdset);//判断某个fd是否在fdset中
三,select的性质
1,select最多只支持1024个fd
2,每次select完成后会清空各fd_set种未就绪的fd,因此:
1,你每次select都要重新用FD_SET加入fd
2,你需要对每个监控的fd调用一次FD_ISSET来判断这个fd是否就绪
这些性质导致select的性能随监控fd数量的增加线性下降, 更好也更流行的方法是epoll, 同时epoll的使用也更为简单
四,用select实现的单线程服务器示例:
代码不够简洁,总之:1,有一个数据结构记录所监控的fd 2,计算maxfd
//...... init listenfd set<int> connected_fds; fd_set rset; int nready; int maxfd; vector<int> del_fds; while(1) { FD_ZERO(&rset); FD_SET(listenfd,&rset); maxfd=listenfd; for(set<int>::iterator iter=connected_fds.begin();iter!=connected_fds.end();iter++) { FD_SET(*iter,&rset); maxfd = maxfd>*iter ? maxfd : *iter; } nready = select(maxfd+1,&rset,0,0,0); if(FD_ISSET(listenfd,&rset)) { printf("a new connection\n"); newfd = accept(listenfd,(sockaddr*)&client_addr,&client_addr_len); if(newfd<=0) { printf("accept failed:%s\n",strerror(errno)); return -1; } connected_fds.insert(newfd); } for(set<int>::iterator iter=connected_fds.begin();iter!=connected_fds.end();iter++) { if(FD_ISSET(*iter,&rset)) { printf("connection %d was selected\n",*iter); ret = read(*iter,recv_buf,sizeof(recv_buf)); if(ret==0) { printf("connection %d closed by remote\n",*iter); close(*iter); del_fds.push_back(*iter); }else if(ret <0){ printf("connection %d err: %s\n",*iter,strerror(errno)); return -1; }else{ recv_buf[ret]='\0'; printf("recv:[%s]\n",recv_buf); strcpy(send_buf,recv_buf); write(*iter,send_buf,strlen(send_buf)); } } } for(vector<int>::iterator iter=del_fds.begin();iter!=del_fds.end();iter++) { connected_fds.erase(*iter); } del_fds.clear(); }
五,poll函数
#include <poll.h>
int poll(struct pollfd* fdarray, unsigned long nfds, int timeout);
参数:
- fdarray: 记录fd信息的数组指针
- nfds: 数组长度
- timeout: 作用与select最后一个参数相同,注意这是一个int,单位是毫秒. INFTIM:阻塞 0 非阻塞 >0:超时时间
poll提供的功能与select基本相同, 可以看错是使用了另一种方式组织管理fd信息,
struct pollfd{
int fd; //fd
short events; //监控的fd状态 一般为 POLLIN或POLLOUT
short revents; //返回就绪的状态
};
如果fd<0, 那么poll将自动忽略这个pollfd
六, poll的性质
- 因为poll函数管理fd的数据是由用户自由分配的数组,因此poll没有管理fd数量的限制
- poll不会修改未就绪的pollfd信息, 但你仍需需要检查每个pollfd的revents来判断该fd是否就绪
比较而言, select的使用比poll更为广泛. 不过相比之下,新一代的epoll有明显的优势
0 0
- 网络编程学习_IO复用:select/poll
- 网络编程中select模型和poll模型学习(linux)
- Unix网络编程学习笔记之第6章 I/O复用:select和poll函数
- linux 网络编程 I/O复用 select,poll ,epoll
- 网络编程 并发执行 线程 进程 IO复用 select poll
- UNIX网络编程:select,epoll,poll比较
- 网络编程 - select、poll、epoll比较
- [Python网络编程]使用select,poll
- Unix网络编程select、poll、epoll比较
- linux网络编程 select,poll,epoll模型
- UNIX网络编程:select,epoll,poll比较
- 网络编程2---select poll epoll
- UNIX网络编程:select,epoll,poll比较
- Unix网络编程代码 第6章 I/O复用:select、poll和epoll函数
- UNIX网络编程——I/O复用:select和poll函数
- UNIX网络编程--I/O复用:select函数和poll函数讲解(六)
- UNIX网络编程--I/O复用:select函数和poll函数讲解(六)
- UNIX网络编程——I/O复用:select和poll函数
- 28 Android 从sdcard 卡下删除文件
- jquery-ajax请求后台数据转换json显示在select下拉列表
- 动态加载资源(云风的blog)
- install jdk in ubuntu
- 库里稚嫩的脸庞背后辛酸故事
- 网络编程学习_IO复用:select/poll
- 【磁盘处理相关方法】3,得到最空闲的磁盘
- HDFS 用户手册(Apache Hadoop 2.1.1-beta)
- 29 Android 保存文件至Sdcard卡
- Http协议详解
- C++ string大小写转换
- 30 Android 自定义文件夹名字 的路径
- 关于Cocos2d-x书籍
- C语言常用排序——直接插入,冒泡,选择,希尔,快速,堆排序