IO多路复用——select

仅一个线程、进程处理并发

IO多路转接(复用)之select

        跨平台适用linux,windows  底层:线性表

IO多路转接(复用)之poll

        适用linux  底层:线性表

IO多路转接(复用)之epoll

        适用linux  底层:红黑树(效率高)

多线程/多进程并发和IO多路转接的并发处理流程进行对比(服务器端):

多线程/多进程并发

  • 主线程/父进程:调用 accept()监测客户端连接请求
  • 如果没有新的客户端的连接请求,当前线程/进程会阻塞
  • 如果有新的客户端连接请求解除阻塞,建立连接
  • 子线程/子进程:和建立连接的客户端通信
  • 调用 read() / recv() 接收客户端发送的通信数据,如果没有通信数据,当前线程/进程会阻塞,数据到达之后阻塞自动解除
  • 调用 write() / send() 给客户端发送数据,如果写缓冲区已满,当前线程/进程会阻塞,否则将待发送数据写入写缓冲区中

IO多路转接并发

  • 使用IO多路转接函数委托内核检测服务器端所有的文件描述符(通信和监听两类),这个检测过程会导致进程/线程的阻塞,如果检测到已就绪的文件描述符阻塞解除,并将这些已就绪的文件描述符传出
  • 根据类型对传出的所有已就绪文件描述符进行判断,并做出不同的处理
  • 监听的文件描述符:和客户端建立连接
  • 此时调用accept()是不会导致程序阻塞的,因为监听的文件描述符是已就绪的(有新请求)
  • 通信的文件描述符:调用通信函数和已建立连接的客户端通信
  • 调用 read() / recv() 不会阻塞程序,因为通信的文件描述符是就绪的,读缓冲区内已有数据
  • 调用 write() / send() 不会阻塞程序,因为通信的文件描述符是就绪的,写缓冲区不满,可以往里面写数据

与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

select

 函数原型

#include<sys/select.h>
struct timeval {
    time_t      tv_sec;         /* seconds */
    suseconds_t tv_usec;        /* microseconds */
};

int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds, struct timeval * timeout)

返回值:三个集合所有满足条件的文件描述符的个数

函数参数:

nfds:委托内核要检测检测的文件描述符中最大的一个 + 1

        线性表实现,这个值是循环结束的条件,不知道就写最大的1024

        在Window中这个参数是无效的,指定为-1即可

readfds: 文件描述符的集合,文件描述符对应的读缓冲区
writefds: 文件描述符的集合,文件描述符对应的写缓冲区
exceptfds:文件描述符的集合,文件描述符是否有异常状态

timeout:指定select函数检测的时长,用来强制解除select()函数的阻塞的
        NULL:函数检测不到就绪的文件描述符会一直阻塞。
        等待固定时长(秒):函数检测不到就绪的文件描述符,在指定时长之后强制解除阻塞,函数返回0
        0:不等待,函数不会阻塞。

初始化fd_set类型的参数
// 将文件描述符fd从set集合中删除 == 将fd对应的标志位设置为0        
void FD_CLR(int fd, fd_set *set);
// 判断文件描述符fd是否在set集合中 == 读一下fd对应的标志位到底是0还是1
int  FD_ISSET(int fd, fd_set *set);
// 将文件描述符fd添加到set集合中 == 将fd对应的标志位设置为1
void FD_SET(int fd, fd_set *set);
// 将set集合中, 所有文件文件描述符对应的标志位设置为0, 集合中没有添加任何文件描述符
void FD_ZERO(fd_set *set);

内核实现细节

在select()函数中第2、3、4个参数都是fd_set类型,它表示一个文件描述符的集合,类似于信号集 sigset_t,这个类型的数据有128个字节,也就是1024个标志位,和内核中文件描述符表中的文件描述符个数是一样的。

这块内存中的每一个bit 和 文件描述符表中的每一个文件描述符是一一对应的关系

首先,将要检测的集合在内核中做了一份拷贝,内核基于拷贝的集合进行检测

下图fd_set中存储了要委托内核检测读缓冲区的文件描述符集合。

  • 如果集合中的标志位为0代表不检测这个文件描述符状态

如果集合中的标志位为1代表检测这个文件描述符状态

内核在遍历这个读集合的过程中,如果被检测的文件描述符对应的读缓冲区中没有数据,内核将修改这个文件描述符在读集合fd_set中对应的标志位,改为0,如果有数据那么这个标志位的值不变,还是1。然后将结果更新到送检的读集合:

select处理服务器并发操作

基本流程

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值