# TinyWebServer **Repository Path**: caan/TinyWebServer ## Basic Information - **Project Name**: TinyWebServer - **Description**: Linux下C++轻量级Web服务器 - **Primary Language**: C++ - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2022-12-02 - **Last Updated**: 2022-12-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TinyWebServer Linux下C++轻量级Web服务器 #### 1. 同步I/O模拟proactor模式 proactor模式中, - 主线程和内核负责处理读写数据、接受新连接等I/O操作。 - 工作线程仅负责业务逻辑,如处理客户请求等。 #### 2. 线程池 ###### 流程: - 维护一个线程池 (array) 和请求事件队列 (list)。 - 主线程为异步线程,使用IO多路复用技术 (epoll) 监听所有socket上的事件。 - 若有新请求到来,主线程接收得到新的连接 socket,然后往 epoll 内核事件表中注册该 socket 上的读写事件。 - 如果连接socket上有读写事件发生,主线程从socket上接收数据,并将数据封装成请求对象插入到请求队列中。 - 工作线程从请求队列中取出任务,完成业务逻辑处理。 - 以上操作请求队列时需要加锁。 ###### 优势: - 降低资源消耗。使用线程池可以避免频繁的创建线程和销毁线程,线程池中线程可以重复使用。 - 提高响应速度。当请求到达时,由于线程池中的线程已经创建好了,使用线程池,可以省去线程创建的这段时间。 - 提高线程的可管理性。使用线程池,可以对线程进行统一分配、调优和监控。 #### 3. HTTP 报文处理 - 浏览器端发出 http 连接请求,服务器端主线程创建 http 对象接收请求并将所有数据读入对应 buffer,将该对象插入任务队列,工作线程从任务队列中取出一个任务进行处理。 - 工作线程取出任务后,通过主、从状态机对请求报文进行解析。 - 解析完之后,生成响应报文,写入buffer,返回给浏览器端。 #### 4. 定时器 主要是为了定期处理非活动连接。 - 将连接资源、定时事件和超时时间封装为定时器类。 - 定时器容器为带头尾结点的升序双向链表,具体的为每个连接创建一个定时器,将其添加到链表中,并按照超时时间升序排列。 - 统一事件源:将信号事件与其他事件一起通过epoll来监测,根据不同事件的对应逻辑使用定时器。 - 浏览器与服务器新建连接时:创建该连接对应的定时器,添加到链表上 - 关闭连接时:销毁该连接的定时器对象,从链表上移除对应定时器 - 读写事件和异常事件:更新超时时间,将对应定时器后移 - 定时信号:从头开始遍历定时器链表,断开超时连接,删除对应的定时器,遇到首个未超时即可跳出 #### 5. 日志 - 使用单例模式创建日志系统,对服务器运行状态、错误信息和访问数据进行记录。 - 同步写入与异步写入 - 同步:日志写入函数与工作线程串行执行,由于涉及到I/O操作,当单条日志比较大的时候,同步模式会阻塞整个处理流程。 - 异步:将所写的日志内容先存入阻塞队列,创建一个写线程,从阻塞队列取出内容写入日志文件。 #### 6. 数据库连接池 - 单例模式创建数据库连接池。 - 工作线程从数据库连接池取得一个连接,访问数据库中的数据,访问完毕后将连接交还连接池。 - 使用信号量进行同步,每次取出连接,信号量减1,释放连接加1,若连接池内没有连接了,则阻塞等待。 #### 7. 待完成工作 - 时间轮算法实现定时器 - Redis缓存 #### 8. 框架 ![frame](images/frame.jpg) #### 致谢 《Linux高性能服务器编程》 《UNIX网络编程》 [@markparticle](https://github.com/markparticle/WebServer) [@linyacool](https://github.com/linyacool/WebServer) [@EZLippi](https://github.com/EZLippi/WebBench)