UNIX网络编程读书笔记:select函数
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函数的更多相关文章
- UNIX网络编程--读书笔记
会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...
- UNIX网络编程读书笔记:简介
认知套接口编程接口 理解原始套接口(raw socket)的概念 值得注意的是,客户和服务器是典型的用户进程,而TCP和IP协议则通常是系统内核协议栈的一部分. 上图中在TCP和UDP之间留有间隙 ...
- Unix 网络编程 读书笔记1
第一章: C/C++语言提供两种不同的编程模式:IPL32和PL64.► IPL32 ● 表示integer/pointer/long三种数据类型是32位(4个字节),在这种模式下,提供32位的地址空 ...
- UNIX网络编程读书笔记:原始套接口
概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...
- UNIX网络编程读书笔记:套接口选项
概述 有很多方法来获取和设置影响套接口的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接口. ...
- UNIX网络编程读书笔记:名字与地址转换
概述 在名字和数值地址间进行转换的函数: gethostbyname和gethostbyaddr:在主机名字与IPv4地址之间进行转换.仅仅支持IPv4. getservbyname和getservb ...
- UNIX网络编程读书笔记:poll函数
poll函数提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息. poll函数原型 #include <poll.h> int poll(struct pollfd * ...
- UNIX网络编程读书笔记:pselect函数
函数原型 pselect函数是由POSIX发明的,其原型如下: #include <sys/select.h> #include <signal.h> #include < ...
- UNIX网络编程读书笔记:shutdown函数
终止网络连接的通常方法是调用close函数.不过close有两个限制,却可以使用shutdown来避免. close 把描述字的引用计数减1,仅在该计数变为0时才关闭套接口.使用shutdown可以不 ...
随机推荐
- [转载]mac软件
效率之王:Afred小帽子:通过前人的配置,替代掉了 有道词典.发音工具.开关机.快速搜索.地图.Spotlight等应用. 主力编辑器:Atom因为高颜值.强大的插件和预览功能 取代了之前的subl ...
- Redis学习篇(三)之Key相关操作
KEYS 作用:返回所有的给定模式的key 语法:KEYS pattern 通配符: *: 任意个字符 ?: 任意一个字符 []: 匹配[]之间的字符 [a-z] [A-Z] \x: 匹配特殊字符 ? ...
- [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)
4012: [HNOI2015]开店 Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 2168 Solved: 947[Submit][Status] ...
- PHP_EOL 换行符
换行符unix系列用 \nwindows系列用 \r\nmac用 \rPHP中可以用PHP_EOL来替代,以提高代码的源代码级可移植性 如: <?php echoPHP_EOL; ...
- ZOJ 3213 Beautiful Meadow 简单路径 插头DP
简单路径的题目,其实就是在状态后面多记了有多少个独立插头. 分类讨论独立插头: 1.只存在上插头或者左插头,可以选择作为独立插头. 2.都不存在上插头和左插头,选择作为独立插头的同时要标号为新的连通块 ...
- 洛谷P4009 汽车加油行驶问题
题目描述 给定一个 N \times NN×N 的方形网格,设其左上角为起点◎,坐标(1,1)(1,1),XX 轴向右为正, YY 轴向下为正,每个方格边长为 11 ,如图所示. 一辆汽车从起点◎出发 ...
- Java实现-每天三道剑指Offre(2-4)
实现一个单例模式 /** * 面试题2:实现单例模式 * * @author qiuyong 饿汉式 */ public class Singleton01 { private Singleton01 ...
- mysql中如何比较日期
做项目,需求是要做一个统计的功能,首次进入默认显示今天以及七天前的数据,这个很好解决. 然后就是用户点击日历插件选择日志,根据日期来统计当天的情况,我数据库里存的时间是使用的时间戳 前台获取到的日期是 ...
- 解决因为google cdn无法访问导致无法打开stackoverflow等网站的方法
许多网站使用了Google的CDN来加速Jquery之类的库来加速网站访问,但由于方校长发福利的原因,导致这些网站很容易出现无法加载"ajax.googleapis.com"而出现 ...
- Druid如何自动根据URL自动识别DriverClass的
Druid是根据url前缀来识别DriverClass的,这样使得配置更方便简洁. 前缀 DriverCLass 描述信息 jdbc:odps com.aliyun.odps.jdbc.OdpsDri ...