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_SETFD_CLRFD_ISSETFD_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...

转自:

1、select函数及fd_set介绍

select(),fd_set(),fd_isset()的更多相关文章

  1. [转帖]select提高并发,select和poll、epoll的区别(杂)

    同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. https://www.2cto.com/kf/20161 ...

  2. 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结

    相关资料 IO基本概念 Linux环境 同步异步阻塞非阻塞 同步与异步 阻塞与非阻塞 IO模型Reference Link 阻塞IO模型 非阻塞IO模型 IO复用模型 信号驱动异步IO模型 异步IO模 ...

  3. select,poll,epoll之间的区别

    (1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替.而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替, ...

  4. 理解select,poll,epoll实现分析

    mark 引用:http://janfan.cn/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html 文章 select()/poll ...

  5. select,poll,epoll,selectors

    一 了解select,poll,epoll IO复用:为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象, 为此,咱们来理解下复用在通信领域的使用,在通信领域中为了 ...

  6. SQLServer并发问题,先SELECT后UPDATE,避免并发脏读情况解决

    在SQL Server中,需要对数据操作进行先SELECT 之后UPDATE,对于这样的操作,如果出现高并发,可能导致脏读情况的发生.不能保证数据的同步. 解决方案是在事物中对表进行加更新锁: 事务一 ...

  7. jquery select取值,赋值操作

    select">jquery select取值,赋值操作 一.获取Select 获取select 选中的 text : $("#ddlRegType").find( ...

  8. 【Go入门教程7】并发(goroutine,channels,Buffered Channels,Range和Close,Select,超时,runtime goroutine)

    有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行. goroutine goroutine是Go并行设计的核心.goro ...

  9. easyui 》 radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中

    获取一组radio被选中项的值var item = $('input[@name=items][@checked]').val();获取select被选中项的文本var item = $(" ...

随机推荐

  1. 01-CentOS 8.1安装 Docker

    官方参考地址:https://docs.docker.com/install/linux/docker-ce/centos/ 里面包含包下载地址:https://download.docker.com ...

  2. JDBC代码的优化

    JDBC代码简化以及PreparedStatement和Statement接口 抽取 JDBC的Bug sql语句可以拼接导致登录功能中如果用户名或者密码中出现'or'2'='2则一定可以登录的bug ...

  3. ReactRouter的实现

    ReactRouter的实现 ReactRouter是React的核心组件,主要是作为React的路由管理器,保持UI与URL同步,其拥有简单的API与强大的功能例如代码缓冲加载.动态路由匹配.以及建 ...

  4. django 组件 自定义过滤器 自定义标签 静态文件配置

    组件 将一些功能标签写在一个html文件里,这个文件作为一个组件,如果那个文件需要就直接拿过来使用即可: 这是title.html文件,写了一个导航栏,作为一个公用的组件 <div style= ...

  5. secrets 管理工具 Vault 的介绍、安装及使用

    原文:https://ryan4yin.space/posts/expirence-of-vault/ Vault 是 hashicorp 推出的 secrets 管理.加密即服务与权限管理工具.它的 ...

  6. 【9k字+】第二篇:进阶:掌握 Redis 的一些进阶操作(Linux环境)

    九 Redis 常用配置文件详解 能够合理的查看,以及理解修改配置文件,能帮助我们更好的使用 Redis,下面按照 Redis 配置文件的顺序依次往下讲 1k 和 1kb,1m 和 1mb .1g 和 ...

  7. mysql的安装使用及其用户管理

    mysql的安装使用及其用户管理   一.mariadb安装 搭建yum源 [mariadb] name = MariaDB baseurl = http://mirrors.ustc.edu.cn/ ...

  8. C#高级编程第11版 - 第五章 索引

    [1]5.1 泛型概述 1.通过泛型,你可以创建独立于特定类型(contained types)以外的方法和类,而不用为不同类型编写多份同样功能的代码,你只需要创建一个方法或者类. 2.泛型类使用泛型 ...

  9. Before you launch a goroutine, know when it will stop The Zen of Go

    The Zen of Go https://the-zen-of-go.netlify.app/ Ten engineering values for writing simple, readable ...

  10. 文件系统层次结构标准 Linux 系统目录结构

    https://zh.wikipedia.org/wiki/文件系统层次结构标准 多数Linux发行版遵从FHS标准并且声明其自身政策以维护FHS的要求. [3] [4] [5] [6] 但截至200 ...