reactor把对面向io的处理转换为对面向事件的处理
面向io处理:https://editor.youkuaiyun.com/md?articleId=134064159
一、概念理解
1.io 函数 都有两个作用 io 检测 和io操作 例如:
a.int clientfd = accpet(listenfd,&addr,&len); 检测全连接队列是否有数据
b.int n = read(clientfd,buf,sz);//检测读缓存区是否有数据 有就读出来
c.int n = write(clientfd,buf,zs);//检测写缓存区是否有空间 有就往缓冲区写
2.io多路复用 检测多个io是否就绪 不具备io操作
为什么reactor把io就绪检测功能丢给io多路复用来做而不是让io函数自己检测?
如果是的话 阻塞的io每个连接都需要一个线程
非阻塞io 每个连接都要 while循环 在应用层检测
3.服务器接受连接?(客户端连接到服务器)
监听listenfd的读事件
服务器主动连接?(服务器连接第三方 mysql等)
监听connectfd的写事件
服务器怎么读取客户端数据?
注册clientfd的读事件EPOLLIN
服务端怎么给客户端发送数据?
1.int n = write(fd,buf,sz);
2.if(n<sz) 一次没写完,需要注册写事件 ,写缓冲区满了,让epoll帮我们检测写缓冲区是否有空间。有空间了通过写事件EPOLLOUT 通知。
二、reactor 模型有三个重要的组件
多路复用器:有操作系统提供,在linux上一般是select,poll,epoll等系统调用
事件分发器:将多路复用器中返回的就绪事件分到对应的处理函数中
事件处理器:负责处理特定事件的处理函数 如,read,accept,write
三、具体流程
注册读就绪事件和相应的事件处理器;
事件分离器等待事件;
事件到来,激活分离器,分离器调用事件对应的处理器;
事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制
权。
四、Reactor 模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:
1.响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;
2.编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进
程的切换开销;
3.可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;
4.可复用性,reactor 框架本身与具体事件处理逻辑无关,具有很高的复用性;
Reactor 模型开发效率上比起直接使用 IO 复用要高,它通常是单线程的,设计目标是
希望单线程使用一颗 CPU 的全部资源,但也有附带优点,即每个事件处理中很多时候可以
不考虑共享资源的互斥访问。可是缺点也是明显的,现在的硬件发展,已经不再遵循摩尔定
律,CPU 的频率受制于材料的限制不再有大的提升,而改为是从核数的增加上提升能力,
当程序需要使用多核资源时,Reactor 模型就会悲剧, 为什么呢?
如果程序业务很简单,例如只是简单的访问一些提供了并发访问的服务,就可以直接开
启多个反应堆,每个反应堆对应一颗 CPU 核心,这些反应堆上跑的请求互不相关,这是完
全可以利用多核的。例如 Nginx 这样的 http 静态服务器。
五、伪代码实现
while(true)
{
int n = epoll_wait(epfd,evs,evs_size,tiomeout);
for(int i = 0; i< n ;i++)
{
epoll_enent ev = evs[i];
if(en & epollin)
{
listenfd 读事件 新事件到达 accept
clientfd 这条连接发送数据了 read
}
else
{
connectfd 写事件 连接建立成功 可以write
clientfd 这条写缓冲区有空间可以写了
}
}
}