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. SVM 支持向量机算法-实战篇

    公号:码农充电站pro 主页:https://codeshellme.github.io 上一篇介绍了 SVM 的原理和一些基本概念,本篇来介绍如何用 SVM 处理实际问题. 1,SVM 的实现 SV ...

  2. Windows下nginx设置开机自启动

    第一步:下载 WinSW https://github.com/winsw/winsw/releases/download/v2.10.3/WinSW.NET4.exe 64位系统 https://g ...

  3. Django-发上云服务器遇到的问题

    1.服务器启动后外网访问显示A server error occurred. Please contact the administrator. 解决方法:原文:https://www.cnblogs ...

  4. linux设备注册

    一.分配cdev cdev表示字符设备,使用cdev_alloc函数,cdev_alloc函数原型如下: /** * cdev_alloc() - allocate a cdev structure ...

  5. 聊一聊:Service层你觉得有用吗?

    前段日子在社群(点击加入)里看到有人讨论关于Service层接口的问题,DD也经常碰到周围的新人有问过一些类似的问题:一定要写个Service层的接口吗?Service层的接口到底用做什么用的呢?好像 ...

  6. 虚拟化kvm的搭建

            虚拟化, 是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机 ,在一台计算机上同时运行多个逻辑计算机,每台逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不 ...

  7. 提供一个HDFS内的文件的路径,对该文件进行创建和删除操作。如果文件所在目录不存在,则自动创建目录。

    1 import java.text.SimpleDateFormat; 2 3 import org.apache.hadoop.fs.FSDataOutputStream; 4 import or ...

  8. Prometheus为你的SpringBoot应用保驾护航

    前面我们介绍了Prometheus的作用和整体的架构,相信大家对Prometheus有了一定的了解. 具体可以查看这篇文章:https://mp.weixin.qq.com/s/QoAs0-AYy8k ...

  9. 客户端负载均衡Ribbon

    客户端负载均衡Ribbon 一.Ribbon是什么 二.Ribbon实现客户端负载均衡 三.Ribbon负载均衡策略 四.Rest请求模板类解读 4.1 RestTemplate的GET请求 第一种: ...

  10. 4. DHCP配置(Windows2012)

    1.点击服务器管理器 2.选择添加角色和功能 3. 按照添加角色和功能向导来添加 保持默认,下一步 保持默认,下一步 保持默认,下一步 勾选DHCP服务器,在弹出的小窗点击添加功能. 保持默认,下一步 ...