目录
5.select检测的集合fd_set和文件描述符表的对应关系
1.什么是多路IO转接
2.SELECT函数是如何工作
3.select函数的细节
> 主旨思想:
>
> - 先构造一张有关文件描述符的列表, 将要监听的文件描述符添加到该表中
> - 调用一个函数,监听该表中的文件描述符,直到这些描述符表中的一个进行I/O操作时,该函数才返回。
>
> - 该函数为阻塞函数
>
> - 函数对文件描述符的检测操作是由内核完成的
> - 在返回时,它告诉进程有多少(哪些)描述符要进行I/O操作。
>
> 特点:
>
> - 跨平台
> - 最大只能检测1024个文件描述符
> - 写死在内核中的, 只能改内核才行
> - 内核在检测的时候是线性遍历
> - epoll检测的时候树状遍历
> - select检测的效率会随着检测的文件描述符数量的上升儿降低
4.文件描述符集合操作函数
// select 是如何实现IO转接的?
1. select是一个跨平台的函数, linux和window平台都可以使用
2. 我们调用这个函数, 该函数会调用相对应的平台的系统api, 委托操作系统执行某些操作
3. 在调用select的时候需要通过参数的形式将要检测的文件描述符的集合传递给内核,
内核根据这个集合进行文件描述符的状态检测
- 读集合: 要检测这一系列文件描述符的读缓冲区 (若干个文件描述符 = 监听的 + 通信的)
- 监听的文件描述符, 看有没有新的客户端连接
- 通信的文件描述符, 看有通信数据达到
- 写集合: 委托内核检测集合中的文件描述符对应的写缓冲区是否可写
- 通信的文件描述符
- 异常集合: 检测集合中文件描述符进行读写操作的时候是否有异常
5.select检测的集合fd_set和文件描述符表的对应关系
内核根据传递的集合中的数据, 对文件描述符表进行线性检测, 如果有满足条件的文件描述符, 内核会通知调用者
- 满足条件是怎么回事?
- 对于读集合: 文件描述符对应的读缓冲区中有数据
- 对于写集合: 文件描述符的写缓冲区可写(写缓冲区不满)
- 对于异常集合: 读写操作出现了错误,
- 内核如何通知调用者:
- 内核会将用户传递给内核的读/写/异常集合进行修改, 得到新的数据
6.select函数的使用流程
最终用户得到的信息?
1. 知道委托内核检测的集合中一共有多少个文件描述符状态发生了变化
2. 通过检测内核传出的读/写/异常集合可以判断出是哪个文件描述符发生了状态变化
```
```c
7.使用select处理服务器通信-1
fd_set是一种数据类型
#include <sys/select.h>
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
fd_set ==> 类型 long int num[32];
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
参数:
- nfds: 这个值是检测的读/写/异常集合中最大的文件描述符值+1
- 读集合检测文件描述符: 5, 6, 7, 8
- 写集合检测.........: 9, 10, 11, 12
- 异常集合...........: 5, 6, 7, 8, 9, 10, 11, 12
- 根据上表描述, nfds值 == 12+1
- 内核遍历的文件描述符表是线性遍历, nfds是遍历结束的标志
8.使用select处理服务器通信-2
- 常用
- 两种情况:
- 判断有没有新连接
- 判断有没有通信数据
- 传入传出参数
- 传入的是委托内核检测的文件描述符集合
- 传出的是内核检测到的满足条件的文件描述符
- 传出的文件描述符个数 <= 传入的文件描述符个数
- writefds: 写集合, 存储若干个文件描述符, 并且都是检测他们的写缓冲区是否可写
- 一般情况下, 文件描述符的写缓冲区都是可写的(有存储空间), 因此这集合很少用
- 不检测指定为NULL
- 传入传出参数
- 传入的是委托内核检测的文件描述符集合
- 传出的是内核检测到的满足条件的文件描述符
- 传出的文件描述符个数 <= 传入的文件描述符个数
9.select集合参数是传入传出要保存原始集合数据
- exceptfds: 异常的集合, 检测集合中文件描述符有没有读写错误
- 一般情况下, 这个集合也很少用
- 不检测指定为NULL
- 传入传出参数
- 传入的是委托内核检测的文件描述符集合
- 传出的是内核检测到的满足条件的文件描述符
- 传出的文件描述符个数 <= 传入的文件描述符个数
10.select服务器代码
- timeout: 表示一个事件段
因为select在检测文件描述符集合的时候需要时间, 默认如果没有满足条件的文件描述符函数会阻塞
- 参数如果指定了一个时间段, 并且在这个时间段中没有检测到有满足条件的文件描述符, 函数解除阻塞
- 如果值为0, 函数调用之后, 马上返回
- NULL, 没有发现集合中满足条件的文件描述符, 函数一直阻塞
返回值:
11.select测试
>0: 检测完成之后, 满足条件的文件描述符的总个数(三个集合的和)
=0: 没有检测到满足条件的文件描述符, 超时时间到了, 强制函数返回
-1: 函数调用失败了
```
```c
// fd_set类型数据操作函数
// 将文件描述符 fd 从 set 集合中删除
void FD_CLR(int fd, fd_set *set);
// 判断文件描述符 fd 是不是在 set 集合中, 如果在返回1, 如果不在返回0
int FD_ISSET(int fd, fd_set *set);
// 将文件描述符 fd 添加到 set 集合中
void FD_SET(int fd, fd_set *set);
// 清空set集合中设置的所有数值, 一般用于初始化
void FD_ZERO(fd_set *set);
```
```c
/*