reactor模式的一些总结

一. 网络编程应该关注的问题

  1. 连接建立
  2. 连接断开
  3. 消息到达
  4. 消息发送

二. 网络IO的职责

2.1 操作 IO

只能使用 io 函数来进行操作;分为两种操作方式:阻塞 io 和非阻塞 io;

2.1.1 操作方式

阻塞和非阻塞
差异:在数据未就绪时是否返回

reactor模式的一些总结_第1张图片
reactor模式的一些总结_第2张图片
连接建立:
listen():在 listen() 函数中,第二个参数指定了已连接但未接受(accept)的队列的最大长度。这个参数告诉操作系统在拒绝新的连接之前,能够接受多少个连接。
accept(): 非阻塞下,如果没有客户端与服务端建立连接,那么accept会返回-1。

连接断开:
主动
close(); shutdown()
客户端shutdown关闭了写端,那么服务端就是读端关闭了。
被动
0 = read(): 服务端的读端关闭了
-1 = write() && errno = EPIPE :服务端的写端关闭了

连接到达
read:
read = -1 返回EWOULDBLOCK : 读缓冲区没有数据。
read = -1 返回EINTR : 被中断打断了

消息发送:

write:
write= -1 返回EWOULDBLOCK : 写缓冲区满了数据。
write = -1 返回EINTR : 被中断打断了

检测 IO

io 函数本身可以检测 io 的状态;但是只能检测一个 fd 对应的状态;io 多路复用可以同时检测多个 io 的状态;区别是:io函
数可以检测具体状态;io 多路复用只能检测出可读、可写、错误、断开等笼统的事件;

检测IO就是检测IO的就绪状态,也就是 IO多路复用(检测多个连接的就绪状态)

reactor模式的一些总结_第3张图片

主要介绍epoll

  1. epoll_create() 会在内核创建一个红黑树和一个双端list等
  2. epoll_ctl() 注册事件,当添加一个事件时候,和网卡的驱动建立回调关系,相应事件被触发,那么就调用回调函数,将触发的事件拷贝到rdlist双向链表中
  3. epoll_wait() 会把rdlist中的就绪事件拷贝出来到用户态。epoll_wait的第四个参数是超时时间,如果设置0,epoll_wait 函数将立即返回,不会等待任何事件。这意味着它会立即轮询已注册的文件描述符,查看是否有就绪的事件,如果没有立即就绪的事件,它将返回并允许程序继续执行,而不会阻塞等待。设置为-1会一直阻塞等待,设置为正数表示阻塞等待这样一段时间,再返回。
    reactor模式的一些总结_第4张图片

reactor

IO多路复用 + 非阻塞IO
由IO多路复用来检测IO,使用非阻塞IO操作IO.

  1. reactor为什么搭配非阻塞IO?
    既然IO多路复用已经帮我们检测数据可用的,那为什么还要使用非阻塞IO呢,阻塞的不是一样吗?
    原因:
    多线程环境中, listedfd通常用于去取建立连接的连接,如果同时放到多个epoll去管理,当TCP三次握手建立完成后,这个新的连接放入到内核里面的全连接队列,他会发送信号告诉这多个epoll有新的连接建立, 如果此时在某一个线程里面已经accept出来了,如果此时使用的是阻塞IO,其他的线程就会阻塞在此处,进而无法执行。

边缘出发下,必须使用非阻塞IO,边缘触发的话,在一次事件循环要把readbuffer读空,如果不读空,只有在下次事件触发才能读取剩下的。如果此时readbuffer已经为空了,但是我们使用的是阻塞IO的话,此时程序就会被阻塞。综上所述,边缘触发无论是不是使用reactoer模型,必须使用非阻塞IO

select bug:当某个socket的接收缓冲区有新数据分节到达,然后select 会报告这个socket描述符可读,但是,协议栈检验时,将数据丢弃了,那么此时调用read将无数据可读,如果此时socket设置为阻塞,则会阻塞线程。
2 是不是IO多路复用都要搭配非阻塞IO?

三.单reactor/多reactor的一些开源项目分析理解

redis -> 单reactor

  1. kv,v支持多种数据结构,在内存中操作数据
  2. 命令处理是单线程的

redis为什么使用单reactor?
命令处理是单线程的,核心业务逻辑是单线程的;操作具体命令时间复杂度低

redis怎么处理reactor?

redis做了哪些优化?
reactor模式的一些总结_第5张图片
使用了多线程:read+decode;encode + write 抛到IO线程去处理。

Memcached

  1. KV ,内存数据库(相对简单的KV)
  2. 命令处理是多线程的

怎么处理reactor?
reactor模式的一些总结_第6张图片

主reactor负责接受连接,子reactor的个数由CPU核心的多少决定;然后通过管道pipe的方式, 。

Memcached通常采用单个事件处理器(Reactor)来管理连接和事件,同时使用多个工作线程来处理实际的I/O操作和数据处理。这种模型有助于处理大量并发连接,提高系统的性能和吞吐量。主Reactor负责监听和分派事件,工作线程负责处理实际的I/O操作,这种设计可以更好地利用多核系统的资源,并提高整个系统的并发处理能力

nginx

reactor模式的一些总结_第7张图片

你可能感兴趣的:(C/C++,服务器,c++,开发语言,c语言)