这里写目录标题
- 引入
- 场景
- 多进程并发服务器
- 二级目录
- 二级目录
- 二级目录
- 多线程并发服务器
- 二级目录
- 二级目录
- 二级目录
- 多路IO转接服务器
- 设计思路
- 对比
- 引入
- select函数简介
- 参数介绍
- 第一个参数
- 第234参数
- 返回值
- 对于第234参数的应用
- 对于最后一个参数
- 总结
- 附加操作(附加四个函数)
- select总结
- select函数模型设计思路(用于服务端)
- epoll进阶
- 二级目录
- 二级目录
- 二级目录
引入
场景
现在我们有了服务端和客户端(上图均以终端代替)
我们从客户端连接上服务端,可以进行正常的运行,但是如果此时第二个客户端也连接上服务端的话,第二个客户端是无法正常运行的,因为目前我们只能处理单进程,一对一的服务提供,无法进行多个客户端同时连接,所以,就有了高并发服务器
多进程并发服务器
二级目录
二级目录
二级目录
多线程并发服务器
二级目录
二级目录
二级目录
多路IO转接服务器
设计思路
对比
首先如上图,我们可以看到,之前的多进程并发和多线程并发的设计思路是:
首先服务端会创建一个监听套接字 listen,即lfd,之后该套接字会一直处于阻塞监听状态,循环调用Accept函数,一旦发现有客户端连进来,就生成一个用于连接的cfd套接字,与客户端建立连接,之后lfd再次处于监听,一旦有其他客户端,就让服务端再创建一个用于连接的cfd套接字,去与客户端2连接,…
但是如果这样的话,服务端的压力会很大,服务端会一直处于阻塞监听,所以,我们就引入了多路IO转接服务器
引入
我们不再使用服务器阻塞监听了,假设我们的服务端是老板,他会雇一个秘书select(由内核实现,我们无需实现),负责监听客户端,首先服务端生成一个lfd监听套接字,然后交给select,select通过lfd来监听客户端,一旦有客户端发起连接请求,会先经过select,之后select接到连接请求之后,将连接请求报告给服务端,服务端只有接到select的通知,才会创建出一个cfd与请求的客户端建立连接,而且这时是确定有客户端要来连接,所以,不用阻塞,直接进行创建然后连接即可,之后把该cfd交给select来管理。
所以,如上图所示的例子的话,select有四个监听,一个负责监听是否有新的客户端来请求连接,其他三个负责监听接收客户端那边发来的信息,反馈给服务端,服务端再将处理完后的结果给到select,select再返回给客户端
这样的机制就叫做响应模式,客户端来请求,服务端才会进行连接,学名叫多路IO转接
而不同的秘书,有着不同的功能,除了select之外,还有俩秘书,分别是poll和epoll
select函数简介
参数介绍
第一个参数
首先,在上图左侧是一个文件描述符表,我们要知道,文件描述符是有编号的,他们会收录在文件描述符表中,首先0 1 2 是被占用的,所以,我们自己的文件描述符会从3开始,如上图所示例子的话,我们最大的文件描述符编号是6,但是我们要传入6+1,因为他的内部是一个for循环,循环所有的文件描述符,而循环条件是<,所以应该+1
第234参数
他们的类型都是文件描述符集合的指针,他们都是传入传出参数,即可以从参数传出内容至函数外(因为他们都是指针)
对于第二个参数,形参名字是readfds,从名字我们也能知道,他是负责读事件的,实际上,他是负责管理select监听哪几个套接字的读事件,他是一个文件描述符集合,实际上就是套接字集合,因为一个文件描述符对应一个套接字,如上图r,他的集合里是3 5 6,那说明他监听3号5号6号套接字的读事件(读是站在select的视角来说的,也就是select在读取内容(即客户端发送内容给select))。但是只是监听,是否真正发送读事件还是另一回事
如法炮制,第3、4个参数分别是,站在select的视角来说,监听哪些文件描述符的写事件、以及异常事件
返回值
因为第234都是传入传出参数,他们的返回值还是一个文件描述符集合,返回那些真正执行了对应事件的文件描述符集合(因为传入的只是监听集合,他们是否真正发生对应的事件并不要求)
select函数的返回值是这三个集合返回的文件描述符总数
对于第234参数的应用
他们是文件描述符集合,实际上底层是一个位图,其中下标分别对应不同编号的文件描述符,而他的值只有0、1,所以对于传入readfds来说,只有3、5、6是1,其他都是0,而对于传出readfds来说,只有5、6是1。
因为底层是位图,所以我们肯定会做一些位操作,那么位操作也有对应的函数,如下图
对于最后一个参数
总结
附加操作(附加四个函数)
第一个函数:将某个文件描述符从集合中剔除
第二个函数:判断指定的fd文件描述符是否在集合中
第三个函数:将某个文件描述符加入到集合中
第四个函数:将集合对应的位图中所有的文件描述符对应的二进制位清0
select总结
对于该图,可以看到一般将第二个第三个参数设置为NULL,因为那两个不常用,之所以write不常用,是因为这里是指客户端与select函数之间的交互,一般select不会向客户端进行write操作(用到了再设置),所以,可以设置为NULL,这也是为什么select被叫做监听内核
而timeout参数,设置了监听时长、阻塞监听、非阻塞忙轮询,而我们之前介绍说select模型是一种响应式的服务器,那是因为对于服务器来说,是借助了select,实现了响应式,而针对于select自己来说,只能是那三个模式的一种。所以,我们所说的相应式,是针对服务器说的,而不是select。
select函数模型设计思路(用于服务端)
首先创建一个套接字,返回值为lfd,用于监听连接
之后绑定地址结构
设置监听上限
然后,接下来就要为select函数做准备工作了,创建两个监听集合,均为fd_set类型,之后将allset监听集合清空,然后将lfd加入到allset集合中。然后设置一个循环,?