From 9a1cc1c1a0f40ae32a134e1787470ced001181f7 Mon Sep 17 00:00:00 2001 From: kurt Date: Fri, 9 Sep 2022 17:34:34 +0800 Subject: [PATCH] Update design doc --- ...66\345\217\221\346\250\241\345\236\213.md" | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git "a/\345\271\266\345\217\221\346\250\241\345\236\213.md" "b/\345\271\266\345\217\221\346\250\241\345\236\213.md" index d64d3db..01b2ed0 100755 --- "a/\345\271\266\345\217\221\346\250\241\345\236\213.md" +++ "b/\345\271\266\345\217\221\346\250\241\345\236\213.md" @@ -31,14 +31,21 @@ epoll的触发模式在这里我选择了ET模式,muduo使用的是LT,这两 每个SubReactor持有一个定时器,用于处理超时请求和长时间不活跃的连接。muduo中介绍了时间轮的实现和用stl里set的实现,这里我的实现直接使用了stl里的priority_queue,底层是小根堆,并采用惰性删除的方式,时间的到来不会唤醒线程,而是每次循环的最后进行检查,如果超时了再删,因为这里对超时的要求并不会很高,如果此时线程忙,那么检查时间队列的间隔也会短,如果不忙,也给了超时请求更长的等待时间。 -## 核心结构 - -程序中的每一个类和结构体当然都必不可少,其中能体现并发模型和整体架构的,我认为是有两个: - -* Channel类:Channel是Reactor结构中的“事件”,它自始至终都属于一个EventLoop,负责一个文件描述符的IO事件,在Channel类中保存这IO事件的类型以及对应的回调函数,当IO事件发生时,最终会调用到Channel类中的回调函数。因此,程序中所有带有读写时间的对象都会和一个Channel关联,包括loop中的eventfd,listenfd,HttpData等。 -* EventLoop:One loop per thread意味着每个线程只能有一个EventLoop对象,EventLoop即是时间循环,每次从poller里拿活跃事件,并给到Channel里分发处理。EventLoop中的loop函数会在最底层(Thread)中被真正调用,开始无限的循环,直到某一轮的检查到退出状态后从底层一层一层的退出。 - -## Log +## 核心结构设计 + +程序中的每一个类和结构体当然都必不可少,其中能体现并发模型和整体架构的,我认为是有下面几个类: +#### Server类 + Server是http服务器的包装类,主要负责开启端口监听和启动事件主循环(Main Reactor),其中事件主循环会将新的客户端连接accept,并放入epoll监控的fd队列,交由后面EventLoop(Sub Reactor)来和客户端做socket读写通信(借助于Channel类) +#### Channel类 + Channel是Reactor结构中的“事件”,它自始至终都属于一个EventLoop,负责一个文件描述符的IO事件,在Channel类中保存这IO事件的类型以及对应的回调函数,当IO事件发生时,最终会调用到Channel类中的回调函数。因此,程序中所有带有读写事件的对象都会和一个Channel关联,包括loop中的eventfd,listenfd,HttpData等。 +#### EventLoop +One loop per thread意味着每个线程只能有一个EventLoop对象,EventLoop即是事件循环,每次从poller里拿活跃事件,并给到Channel里分发处理。EventLoop中的loop函数会在最底层(Thread)中被真正调用,开始无限的循环,直到某一轮的检查到退出状态后从底层一层一层的退出。 +#### HttpData类 + HttpData是用来读写socket数据,转换解析http 协议的数据,并做对应的业务处理,具体的read/write handler在事件主循环接受新连接时,在HttpData的构造函数中传入,具体见 + ``` + Server::handNewConn() + ``` +## 日志记录设计 Log的实现了学习了muduo,Log的实现分为前端和后端,前端往后端写,后端往磁盘写。为什么要这样区分前端和后端呢?因为只要涉及到IO,无论是网络IO还是磁盘IO,肯定是慢的,慢就会影响其它操作,必须让它快才行。 这里的Log前端是前面所述的IO线程,负责产生log,后端是Log线程,设计了多个缓冲区,负责收集前端产生的log,集中往磁盘写。这样,Log写到后端是没有障碍的,把慢的动作交给后端去做好了。