select函数概况:

select函数允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或多个事件发生或经历一段指定的时间后才唤醒它。

作为一个例子,我们可以调用select,告知内核仅在下列情况发生时才返回:

(1)集合{1,4,5}中的任何描述字准备好读,或

(2)集合{2,7}中的任何描述字准备好写,或

(3)集合{1,4}中的任何描述字有异常条件待处理,或

(4)已经历了10.2秒。

也就是说,我们调用select告知内核对哪些描述字(就读、写或异常条件)感兴趣以及等待多长时间。我们感兴趣的描述字不局限于套接口;任何描述字都可以使用select来测试。

#include <sys/select.h>
#include <sys/time.h> int select(int maxfdpl, fd_set *readset, fd_set *writeset,
fd_set *exceptset, const struct timeval *timeout);
返回值:就绪描述字的总数目,0——超时,-1——出错

select函数参数介绍:

关于此函数的参数的详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3557584.html。重复内容不再赘述,这里只给出一些补充内容。

timeout参数的const限定词表示它在函数返回时不会被select修改。

但是有些Linux版本会修改这个timeval结构。因此从移植性考虑,我们应该假设该timeval结构在select返回时未被定义,因此每次调用select之前都得对它进行初始化。POSIX规定对该结构使用const限定词。

中间的三个参数readset、writeset和exceptset指定我们要让内核测试读、写和异常条件的描述字。目前支持的异常条件只有两个:

(1)某个套接口的带外数据的到达。

(2)某个已置为分组方式的伪终端存在可从其主端读取的控制状态信息。

如何给这三个参数的每一个指定一个或多个描述字值是一个设计上的问题。select使用描述字集,典型地是一个整数数组,其中每个整数中的每一位对应一个描述字。举例来说,假设使用32位整数,那么该数组的第一个元素对应描述字0-31,第二个元素对应描述字32-63,以此类推。所有这些实现细节都与应用程序无关,它们隐藏在名为fd_set的数据类型和以下四个宏中:

/* fd_set macro */
void FD_ZERO(fd_set *fdset); /* clear all bits in fdset */
void FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fdset */
void FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fdset */
int FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset?*/

描述字集的初始化非常重要,因为作为自动变量分配的一个描述符字集如果没有初始化,那么可能发生不可预期的后果。因此,声明了一个描述符集后,必须用FD_ZERO清除其所有位,然后在其中设置我们关心的各个位。举个例子,以下代码用于定义一个fd_set类型的变量,然后打开描述字1、4和5的对应位:

/* example */
fd_set rset; FD_ZERO(&rset); /* initialize the set: all bits off */
FD_SET(1, &rset); /* turn on bit for fd 1 */
FD_SET(4, &rset); /* turn on bit for fd 4 */
FD_SET(5, &rset); /* turn on bit for fd 5 */

select函数的中间三个参数readset、writeset和exceptset中,如果我们对某一个的条件不感兴趣,就可以把它设为空指针。事实上,如果这三个指针均为空,我们就有了一个比UNIX的sleep函数更为精确的定时器(sleep睡眠以秒为最小单位)。poll函数提供类似的功能。

maxfdpl参数指定待测试的描述符字个数,它的值是待测试的最大描述符字加1(因此我们把该参数命名为maxfdpl),描述字0、1、2……一直到maxfdpl-1均被测试。

头文件<sys/select.h>中定义的FD_SETSIZE常值是数据类型fd_set中的描述字总数,其值通常是1024,不过很少有程序用到那么多描述字。

select函数修改由指针readset、writeset和exceptset所指向的描述字集,因而这三个参数都是值-结果参数。调用该函数时,我们指定所关心的描述字的值,该函数返回时,结果指示哪些描述字已就绪。该函数返回后,我们使用FD_ISSET宏来测试fd_set数据类型中的描述字。描述字集中任何与未就绪的描述字对应的位返回时均清成0。为此,每次重新调用select函数时,我们都得再次把所有描述字集中所关心的位均置为1。

使用select时最常见的两个错误:(1)忘了对最大描述字加1;(2)忘了描述字集是值-结果参数。

select函数返回值:

该函数的返回值表示跨所有描述字集的已就绪的总位数。如果在任何描述字就绪之前定时器时间到,那么返回0。返回-1表示出错。

描述字就绪条件:

1、下列四个条件中的任何一个满足时,一个套接口准备好读:

(1)该套接口接收缓冲区中的数据字节数大于等于套接口接收缓冲区低潮标记的当前大小。对这样的套接口的读操作将不阻塞并返回一个大于0的值(也就是返回准备好读入的数据)。我们可以使用SO_RCVLOWAT套接口选项设置该套接口的低潮标记。对于TCP和UDP套接口而言,其缺省值为1。

(2)该连接的读这一半关闭(也就是接收了FIN的TCP连接)。对这样的套接口的读操作将不阻塞并返回0(也就是返回EOF)。

(3)该套接口是一个监听套接口且已完成的连接数不为0。对这样的套接口的accept通常不会阻塞。

(4)其上有一个套接口错误待处理。对这样的套接口的读操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这些待处理的错误(pending error)也可以通过指定SO_ERROR套接口选项调用getsockopt获取并清除。

2、下列四个条件中的任何一个满足时,一个套接口准备好写:

(1)该套接口发送缓冲区中的可用空间字节数大于等于套接口发送缓冲区低潮标记的当前大小,并且或者(I)该套接口已连接,或者(II)该套接口不需要连接(例如UDP套接口)。这意味着如果我们把这样的套接口设置为非阻塞,写操作将不阻塞并返回一个正值(例如由传输层接受的字节数)。我们可以使用SO_SNDLOWAT套接口选项来设置该套接口的低潮标记。对于TCP和UDP而言,其缺省值通常为2048。

(2)该连接的写这一半关闭。对这样的套接口的写操作将产生SIGPIPE信号。

(3)该套接字早先使用非阻塞式connect已建立连接,并且连接已经异步建立或者connect已经以失败告终。

(4)其上有一个套接口错误待处理。对这样的套接口的写操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这些待处理的错误(pending error)也可以通过指定SO_ERROR套接口选项调用getsockopt获取并清除。

3、如果一个套接口存在带外数据或者仍处于带外标记,那么它有异常条件待处理。

注意:当某个套接口上发生错误时,它将由select标记为既可读又可写。

接收和发送低潮标记的目的在于:允许应用程序控制在select返回可读或可写条件之前,有多少数据可读或有多大空间可用于写。举例来说,如果我们知道除非至少存在64字节的数据,否则我们的应用程序没有任何工作可做,那么可以把接收低潮标记设置为64,以防少于64字节的数据准备好读时,select就唤醒我们。

任何UDP套接口只要其发送低潮标记小于等于发送缓冲区大小(缺省应该总是这种关系)就总是可写的,这是因为UDP套接口不需要连接。

UNIX网络编程读书笔记:select函数的更多相关文章

  1. UNIX网络编程--读书笔记

    会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...

  2. UNIX网络编程读书笔记:简介

    认知套接口编程接口 理解原始套接口(raw socket)的概念   值得注意的是,客户和服务器是典型的用户进程,而TCP和IP协议则通常是系统内核协议栈的一部分. 上图中在TCP和UDP之间留有间隙 ...

  3. Unix 网络编程 读书笔记1

    第一章: C/C++语言提供两种不同的编程模式:IPL32和PL64.► IPL32 ● 表示integer/pointer/long三种数据类型是32位(4个字节),在这种模式下,提供32位的地址空 ...

  4. UNIX网络编程读书笔记:原始套接口

    概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...

  5. UNIX网络编程读书笔记:套接口选项

    概述 有很多方法来获取和设置影响套接口的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接口. ...

  6. UNIX网络编程读书笔记:名字与地址转换

    概述 在名字和数值地址间进行转换的函数: gethostbyname和gethostbyaddr:在主机名字与IPv4地址之间进行转换.仅仅支持IPv4. getservbyname和getservb ...

  7. UNIX网络编程读书笔记:poll函数

    poll函数提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息. poll函数原型 #include <poll.h> int poll(struct pollfd * ...

  8. UNIX网络编程读书笔记:pselect函数

    函数原型 pselect函数是由POSIX发明的,其原型如下: #include <sys/select.h> #include <signal.h> #include < ...

  9. UNIX网络编程读书笔记:shutdown函数

    终止网络连接的通常方法是调用close函数.不过close有两个限制,却可以使用shutdown来避免. close 把描述字的引用计数减1,仅在该计数变为0时才关闭套接口.使用shutdown可以不 ...

随机推荐

  1. 我的OI生涯 第一章

    第一章   一入电竞深似海 我叫WZY,是TSYZ的一名学生. 2016年7月10日,我进了一个叫做oi的坑. 那时的我不知道什么叫竞赛,不知道什么叫编程,不知道什么是c++. 就记得前一天我特意去图 ...

  2. USACO 2017 FEB Gold visitfj 最短路

    题意 有一幅n*n的方格图,n <= 100,每个点上有一个值.从(1,1)出发,走到(n,n),只能走四联通.每走一步花费t,每走三步需要花费走完三步后到达格子的值.求最小花费的值. 拆点,d ...

  3. PAT甲级1033. To Fill or Not to Fill

    PAT甲级1033. To Fill or Not to Fill 题意: 有了高速公路,从杭州到任何其他城市开车很容易.但由于一辆汽车的坦克容量有限,我们不得不在不时地找到加油站.不同的加油站可能会 ...

  4. pm2 相关命令

    pm2 相关命令 转载 2017年02月18日 22:59:48   二.安装 Linux Binaries下载地址:https://nodejs.org/dist cd oneinstack/src ...

  5. python接口自动化25-发xml格式post请求

    前言 post请求相对于get请求多一个body部分,body部分常见的数据类型有以下四种(注意是常见的,并不是只有4种) application/x-www-form-urlencoded appl ...

  6. Java 反照机制中 getMethod()和getDeclaredField()区别

    Java 反射机制中 getMethod()和getDeclaredField()区别 今天在程序中用到java反射机制时,遇到的问题记录一下:我当时遇到的问题是,我用反射getMethod()调用类 ...

  7. iOS:提示框(警告框)控件UIAlertView的详解

    提示框(警告框)控件:UIAlertView   功能:当点击按钮或标签等时,弹出一个提示框,显示必要的提示,然后通过添加的按钮完成需要的功能.   类型:typedef NS_ENUM(NSInte ...

  8. iOS:CoreData数据库的使用一(创建单个数据库表)

    CoreData数据库框架:mac系统自带的数据库,它是苹果公司对sqlite进行封装而来的,既提供了对数据库的主要操作,也提供了具体的视图关系模型. 需要用到三个对象: 1•Managed Obje ...

  9. 数学图形(1.40)T_parameter

    不记得在哪搞了个数学公式生成的图形. vertices = t = to (*PI) r = 2.0 x = r*(*cos(t) - cos(*t)) y = r*(*sin(t) - sin(*t ...

  10. OpenGL: 你不知道的左右手坐标系

    左右手坐标系 众所周知,OpenGL使用的是右手坐标系,而Direct3D使用的是左手坐标系. 除了上面Z轴的方向不一样外,左右手坐标系的还有其他区别: 正向旋转方向:在左手系中用Left-Hand ...