select(),fd_set(),fd_isset()
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的值如下:

图1. 引自https://www.cnblogs.com/wuyepeng/p/9745573.html
然后经过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的操作来完成异步的网络消息处理,具体的实现请看这里的例子。
Over...
转自:
select(),fd_set(),fd_isset()的更多相关文章
- [转帖]select提高并发,select和poll、epoll的区别(杂)
同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. https://www.2cto.com/kf/20161 ...
- 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结
相关资料 IO基本概念 Linux环境 同步异步阻塞非阻塞 同步与异步 阻塞与非阻塞 IO模型Reference Link 阻塞IO模型 非阻塞IO模型 IO复用模型 信号驱动异步IO模型 异步IO模 ...
- select,poll,epoll之间的区别
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替.而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替, ...
- 理解select,poll,epoll实现分析
mark 引用:http://janfan.cn/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html 文章 select()/poll ...
- select,poll,epoll,selectors
一 了解select,poll,epoll IO复用:为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象, 为此,咱们来理解下复用在通信领域的使用,在通信领域中为了 ...
- SQLServer并发问题,先SELECT后UPDATE,避免并发脏读情况解决
在SQL Server中,需要对数据操作进行先SELECT 之后UPDATE,对于这样的操作,如果出现高并发,可能导致脏读情况的发生.不能保证数据的同步. 解决方案是在事物中对表进行加更新锁: 事务一 ...
- jquery select取值,赋值操作
select">jquery select取值,赋值操作 一.获取Select 获取select 选中的 text : $("#ddlRegType").find( ...
- 【Go入门教程7】并发(goroutine,channels,Buffered Channels,Range和Close,Select,超时,runtime goroutine)
有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行. goroutine goroutine是Go并行设计的核心.goro ...
- easyui 》 radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中
获取一组radio被选中项的值var item = $('input[@name=items][@checked]').val();获取select被选中项的文本var item = $(" ...
随机推荐
- 与数论的厮守05:gcd(a,b)=gcd(b,a mod b)的证明
\[设c=gcd(a,b),那么a可以表示为mc,b可以表示为nc的形式.然后令a=kb+r,那么我们就\\ 只需要证明gcd(b,r)=c即可.{\because}r=a-kb=mc-knc,{\t ...
- 核酸检测:让我明白AQS原理
春节越来越近了,疫情也越来越严重,但挡不住叫练携一家老小回老家(湖北)团聚的冲动.响应国家要求去我们做核酸检测了. 独占锁 早上叫练带着一家三口来到了南京市第一医院做核酸检测,护士小姐姐站在医院门口拦 ...
- 配置HDFS的HA
配置前准备: -- 配置hadoop -- 配置ZooKeeper,传送门:https://www.cnblogs.com/zhqin/p/11906106.html 安装配置好hadoop和ZooK ...
- Android使用代码开关Location服务
Android系统中,只有系统设置里面有入口开关位置服务.其他的应用应该怎么去开关这个服务呢? 首先,应用需要有系统权限(签名),在这基础上,我们就可以通过一些手段来实现这个功能. 这里要注意一点,不 ...
- scrapy爬虫 简单入门
1. 使用cmd+R命令进入命令行窗口,并进入你需要创建项目的目录 cd 项目地址 2. 创建项目 scrapy startproject <项目名> cd <项目名> 例如 ...
- Python学习【第8篇】:python中的函数
1.python中函数定义方法 def test(x): "This istest" y = x*2+1 return y vaule = test(2)print(vaule)运 ...
- GeoMesa命令行,索引概述
GeoMesa 一.GeoMesa命令行 查看classpath 创建表 描述表 批量导入数据 解释查询 统计分析 导出feature 删除feature 获取目录中的全部表的名称 删除表 删除目录 ...
- CAS+Tomcat SSL第三方数据证书导入(jks)
首先,为CAS SERVER配置HTTPS 切换到证书 xxx.jks的目录下,查看证书的信息 keytool -list -keystore XXX.jks -storepass **** XX ...
- ajax 用fom提交
$.ajax({ type : "POST", url : "${ctx}/credit/LoanauditCtrl/qwe.do?hetong="+heton ...
- OpenStack (nova 计算服务)
nova介绍 Nova 负责维护和管理云环境的计算资源,Nova这个模块很重要,可以说是 OpenStack 的最核心的服务模块之一,以至于在 OpenStack 的初期版本里大部分的云系统管理功能都 ...