【长文梳理Webserver核心】框架篇

发布于:2024-10-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

感谢前人的总结,让一个小白快速成长,那我也贡献一份自己的力量~

在这里插入图片描述

大框架梳理

先摆图:
在这里插入图片描述
目光先放到最上面的两个小框架,半同步/半反应堆线程池和异步日志系统,日志系统晓得伐?非常重要但不属于项目业务实现的核心,所以咱先主要看这个半同步/反应堆线程池,它在其中维护了一个请求队列,这个队列非常非常重要,主要用来处理请求(废话。。。

在这个线程池中的主线程通过epoll来监听socket,看有没有新请求,并将请求队列中的任务分配给线程池中的工作线程,OK到下一个绿框框了,工作线程可以处理的任务有三类:

  • 日志输出
  • 定时器处理非活动连接
  • 处理HTTP请求

以上就是文字描述的核心业务,如果更加清晰简单描述的话就是下面这样:
在这里插入图片描述
MainReactor将与Client建立的连接发给Acceptor,Acceptor再将连接分配给一些SubReactor的模块,在SubReactor中对具体的连接进行读、编码、计算、解码和写操作(即对client请求的响应)。

上面这句话是我抄的,有没有和我一样看这句话也会冒出很多问题的朋友?
比如,什么是SubReactor,为什么图片上只画了两个,建立什么样的具体连接…

我直接说了,冒出这种问题是因为前置知识不足
这里用的是主从Reactor多线程,图其实画的…我不知道为什么会一传十十传百,我查资料之后感觉有写问题,如果不对还请评论指出在这里插入图片描述下面以我查完资料的思路讲解一下:

我认为正确的图,来源看水印:
在这里插入图片描述
Reactor多线程方案说明:

  • 主Reactor通过Selector监听连接事件,收到通知后。通过Acceptor处理连接事件
  • 当Acceptor处理连接事件之后,MainReactor将事件分配给SubReactor
  • SubReactor将这个事件加入到队列中,并且创建Handler去处理
  • Handler对事件分发到Worker线程池并且进行处理
  • 主Reactor可以对应多个子Reactor

该方案的优点是:

  • 父线程与子线程的数据交互简单职责明确,父线程只负责接收新连接,子线程完成后续的业务处理
  • 父线程与子线程的数据交互简单,Reactor主线程只需要把新连接传给子线程,子线程无需返回数据

现在再看框架就明白多了
框架就了解到这里吧,接下来梳理一下细节

从main函数开始学习

作者在main函数中进行了参数配置,设置日志的相关参数(存储路径、日志等级…),然后实例化了一个主循环对象,初始化了Webserver单例对象,最后启动了Webserver并开启了主循环。

EventLoop mainLoop;
Server myHTTPServer(&mainLoop, threadNum, port);
myHTTPServer.start();
mainLoop.loop();

其中最重要的函数是myHTTPServer.start();mainLoop.loop();,先着重分析他俩

先看第一个函数myHTTPServer.start();
在这里插入图片描述
主要工作:

  • 启动线程池
  • 设置了acceptChannel_的handler,分别为读回调和连接回调
  • 将acceptChannel_加入Poller

可以看出来是做了一些连接操作,但什么是Poller?什么是acceptChannel_?
现在很多还不好解释,我先解释一下acceptChannel_的读回调函数,读回调函数就是有新连接时执行的函数
在这里插入图片描述
他的主要工作是:

  • 通过accept(3)来建立TCP连接
  • 从线程池中获取一个eventLoop事件循环
  • 将建立的新连接放入eventLoop事件循环

再看下mainLoop.loop();
在这里插入图片描述
做了以下工作:

  • 从poller中取出所有活动事件
  • 调用活动事件的回调函数
  • 执行额外的函数
  • 执行超时的回调函数