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的值如下:

然后经过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介绍相关推荐

  1. Linux下IO多路复用之select函数的使用

    select函数的作用: 如果我们的程序里有两个需要阻塞的地方,例如要从服务器读数据,同时还要从键盘上读数据(若不采用阻塞而用查询的方式则大量占用系统资源).这个时候我们就有两处阻塞,你当然可以用多线 ...

  2. Linux select函数的使用

    文章目录 一.select函数 1.fd_set结构体 FD_ZERO FD_SET FD_CLR FD_ISSET 2.timeval 结构体 3.返回值 二.文件描述符就绪条件 三.使用 一.se ...

  3. select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET(转)

    select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型, 原型: int select(int maxfd,fd_set *rds ...

  4. select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

    从别人的博客中转载过来了这一篇文章,经过重新编辑排版之后展现于此,做一个知识点保存与学习. select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复 ...

  5. linux中有fd set函数吗,LINUX下FD_SET介绍

    刚刚了解了linux下select系统调用,函数原型是 #include #include int select(int maxfdpl, fd_set *readset, fd_set *write ...

  6. select函数介绍

    linux编程中select函数用于检测一组socket上是否有事件就绪,这里的事件包括可读.可写.异常事件,其中读事件就绪是指发生以下几种情况: 1. socket内核接收缓冲区的字节数大于等于低水 ...

  7. Linux延时(延迟)函数比较:介绍Linux系统中常用的延时函数sleep、usleep、nanosleep、select和std::sleep_for()的区别和使用场景

    首先,需要了解各个睡眠函数的作用和使用场景. sleep函数用于让进程休眠指定的秒数,适用于需要较长时间的休眠场景: usleep函数用于让进程休眠指定的微秒数,适用于需要较短时间的休眠场景,不精确: ...

  8. Select函数实现原理分析

    转载自 http://blog.chinaunix.net/uid-20643761-id-1594860.html select需要驱动程序的支持,驱动程序实现fops内的poll函数.select ...

  9. socket通信时如何判断当前连接是否断开--select函数,心跳线程,QsocketNotifier监控socket...

    client与server建立socket连接之后,如果突然关闭server,此时,如果不在客户端close(socket_fd),会有不好的影响: QsocketNotifier监控socket的槽 ...

最新文章

  1. webp、jpeg、png三种压缩算法比较
  2. 关于CRTP(Curiously Recurring Template Prattern)的使用
  3. JNDI 在 J2EE 中的角色
  4. [BZOJ1643][Usaco2007 Oct]Bessie's Secret Pasture 贝茜的秘密草坪
  5. JQ:当页面滚动到一定位置之后,让元素固定在顶部,小于位置后恢复原来的位置
  6. python将2个列表list合并到1个列表使用appenden_【新手入门】20个很实用的 Python 学习小技巧...
  7. android 录音原始文件_5分钟短文 | Android证书生成,签名,验证,虽然难,但学一次就够了!...
  8. cf1523A. Game of Life
  9. CISCO PVST+配置和结果验证 per vlan spanning tree(51cto 实验10)
  10. 用css3和jquery实现的渐变的动态进度条
  11. GPU服务器的配置计划
  12. java检测textarea换行_Textarea和Java 换行符
  13. 基于HT for Web矢量实现3D叶轮旋转
  14. 使用rarcrack暴力破解RAR,ZIP,7Z压缩包
  15. 登录oneNote失败解决
  16. 网易云ncm转mp3
  17. WT588D语音芯片 语音模块组
  18. Excel技巧—快速插入空行技巧大集合
  19. Speedoffice(Excel)怎样给文字添加删除线?
  20. 如何查看tkinter可用的字体有哪些

热门文章

  1. spark的内存过小报错
  2. Codeup墓地-问题 A: 最长上升子序列
  3. 【易懂】Java源码角度分析put()与putIfAbsent()的区别——源码分析系列
  4. [leetcode]106.从中序与后序遍历序列构造二叉树
  5. DBSAN密度聚类算法
  6. 数据库原理与应用(SQL Server)笔记 第七章 流程控制语句、系统内置函数
  7. linux curl 多线程,CURL多线程不执行一直在请求
  8. java中字符串的操作_java中字符串的操作
  9. tomcat日志、控制台乱码
  10. 教室工资管理系统c语言课程设计csdn,工资管理系统(C编写)