select函数及fd_set介绍
1. select函数
1. 用途
在编程的过程中,经常会遇到许多阻塞的函数,好像read和网络编程时使用的recv, recvfrom函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在这里,无法执行下面的代码。这时就需要用到非阻塞的编程方式,使用select函数就可以实现非阻塞编程。
select函数是一个轮循函数,循环询问文件节点,可设置超时时间,超时时间到了就跳过代码继续往下执行。
2. 大致原理
select需要驱动程序的支持,驱动程序实现fops内的poll函数。select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用(如可读或写),如果有的话则返回可用资源的文件描述符个数,没有的话则睡眠,等待有资源变为可用时再被唤醒继续执行。详细的原理请看这里
3. 函数定义
该函数声明如下
int select(int nfds, fd_set* readset, fd_set* writeset, fe_set* exceptset, struct timeval* timeout);
参数:
nfds 需要检查的文件描述字个数
readset 用来检查可读性的一组文件描述字。
writeset 用来检查可写性的一组文件描述字。
exceptset 用来检查是否有异常条件出现的文件描述字。(注:错误不包括在异常条件之内)
timeout 超时,填NULL为阻塞,填0为非阻塞,其他为一段超时时间
返回值:
返回fd的总数,错误时返回SOCKET_ERROR
2. fd_set结构体
上面select函数中需要用到两个fd_set形参,这个结构体到底做什么用的呢
fd_set其实这是一个数组的宏定义,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(socket、文件、管道、设备等)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪个句柄可读。
系统提供了FD_SET, FD_CLR, FD_ISSET, FD_ZERO进行操作,声明如下:
FD_SET(int fd, fd_set *fdset); //将fd加入set集合
FD_CLR(int fd, fd_set *fdset); //将fd从set集合中清除
FD_ISSET(int fd, fd_set *fdset); //检测fd是否在set集合中,不在则返回0
FD_ZERO(fd_set *fdset); //将set清零使集合中不含任何fd
下面写一段程序探究一下这几个宏的工作:
#include <WINSOCK2.H>
int main()
{
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(1, &fdset);
FD_SET(2, &fdset);
FD_SET(3, &fdset);
FD_SET(7, &fdset);
int isset = FD_ISSET(3, &fdset);
printf("isset = %d\n", isset);
FD_CLR(3, &fdset);
isset = FD_ISSET(3, &fdset);
printf("isset = %d\n", isset);
return 0;
}
当使用FD_SET添加完1、2、3、7后,fdset的值如下:
然后经过FD_CLR以后,fd_array[2]就被清除了,数组后面的数据依次往前提,即7被放到了fd_array[2]
所以isset前后两次打印的值分别为1和0
3. 小结
select的结果会对fd_set造成影响。例如,对于一个监听的socket:
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"WS2_32.lib")
int main()
{
FD_SET ReadSet;
FD_ZERO(&ReadSet);
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData); //初始化
SOCKET ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); //定义一个监听套接字
//bind等操作这里省略.... //.....
FD_SET(ListenSocket, &ReadSet); //将套接字加入ReadSet集合中
int isset = FD_ISSET(ListenSocket, &ReadSet); //这里并没有通过select对fd_set进行筛选
printf("Before select, isset = %d\n", isset); //所以这里打印结果为1
struct timeval tTime;
tTime.tv_sec = 10;
tTime.tv_usec = 0;
select(0, &ReadSet, NULL, NULL, &tTime); //通过select筛选处于就绪状态的fd
//这时,刚才的ListenSocket并不在就绪状态(没有连接连入),那么就从ReadSet中去除它
isset = FD_ISSET(ListenSocket, &ReadSet);
printf("After select, isset = %d\n", isset); //所以这里打印的结果为0
system("pause");
return 0;
}
所以可以使用select以及fd的操作来完成异步的网络消息处理,具体的实现请看这里的例子
select函数及fd_set介绍的更多相关文章
- (十二)select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型:int select(int maxfd,fd_set *rdset ...
- select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
http://hi.baidu.com/%B1%D5%C4%BF%B3%C9%B7%F0/blog/item/e7284ef16bcec3c70a46e05e.html select函数用于在非阻塞中 ...
- select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET(转)
select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型, 原型: int select(int maxfd,fd_set *rds ...
- select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET (转)
select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型: #include <sys/time.h> ...
- linux网络编程:select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET(转)
从别人的博客中转载过来了这一篇文章,经过重新编辑排版之后展现于此,做一个知识点保存与学习. select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复 ...
- select函数的介绍和使用
我们所使用的I/O模型一共有五种. 分别为阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O. 所谓I/O复用就是指管理多个I/O文件描述符,一般会使用(select,poll,epol ...
- 一.Select 函数详细介绍【转】
转自:http://www.cnblogs.com/hjslovewcl/archive/2011/03/16/2314330.html Select在Socket编程中还是比较重要的,可是对于初学S ...
- 转 select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型:int select(int maxfd,fd_set *rdset ...
- Linux驱动 - select函数介绍
一.select 函数介绍 select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型: #include & ...
随机推荐
- 服务器同时安装python2支持的py-faster-rcnn以及python3支持的keras
最近把服务器折腾一下,搞定这两个.
- Java之四大元注解@Target、@Retention、@Documented、@Inherited
什么叫做元注解?? ==>用于注解[注释]的注解就叫做元注解 注解叫做:元数据,标签,注释 元注解[数据]--->注解--->标记代码 1.@Target : ...
- springboot初体验-不知道怎么创建spring-boot项目?
https://spring.io/projects/spring-boot/ 在以上地址找到 Quick start Bootstrap your application with Spring I ...
- [Leetcode] 1120. Maximum Average Subtree
Given the root of a binary tree, find the maximum average value of any subtree of that tree. (A subt ...
- C# 网络连接中异常断线的处理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(设置心跳)
C# 网络连接中异常断线的处理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(设置心跳) 在使用 TcpClient 网络连接中常常会发生客户端连接异常断 ...
- quota磁盘配额
一.什么是磁盘配额 磁盘配额从字面意思上看就是给一个磁盘配置多少额度,而quota就是有多少限额的意思,所以总的来说就是限制用户对磁盘空间的使用量.因为Linux是多用户多任务的操作系统,许多人公用磁 ...
- Java自学-类和对象 枚举类型
枚举类型 步骤 1 : 预先定义的常量 枚举enum是一种特殊的类(还是类),使用枚举可以很方便的定义常量 比如设计一个枚举类型 季节,里面有4种常量 public enum Season { SPR ...
- tomcat重启session不失效问题
本地写代码每次重启都要重新登录浪费了很多时间,如何重启不用重新登录呢,只要让tomcat在关闭时将session写入文件中,在启动时从文件中读取session即可. 只需在conf/context.x ...
- 【转载】C#中ArrayList集合类和List集合类的比较
List集合类和ArrayList集合类都是C#语言中用于存储集合数据的集合类,两者都可灵活的插入.删除以及访问元素等等.但List集合和ArrayList集合的差别还是挺大的,首先List集合类是泛 ...
- Java语言的介绍
1. 计算机语言 语言:沟通交流的方式 计算机语言:人与计算机之间的交流方式 java是一门计算机编程语言,也是意大利自行车品牌 软件工程师,java开发工程师 <--------------- ...