WebServer上面的问题

WebServer 上的一些记录

之前的学的开源项目,现在过来总结一下。

1、简单介绍一下这个项目

用C++实现的一个高性能WebServer,经过webbenchh 开源测压工具测试可以实现1w+QPS(Query Per Second) .

2、里面的一些功能

  • 利用IO复用技术Epoll与线程池的思想实现多线程的Reactor高并发模型;
  • 利用正则与状态机解析HTTP请求报文,实现处理静态资源的请求;
  • 利用标准库容器封装char,实现自动增长的缓冲区;
  • 基于小根堆实现的定时器,关闭超时的非活动连接;
  • 利用单例模式与阻塞队列实现异步的日志系统,记录服务器运行状态;
  • 利用RAII机制实现了数据库连接池,减少数据库连接建立与关闭的开销,同时实现了用户注册登录功能。

3、Reactor技术讲解一下

服务器程序通常需要处理三类事件,IO事件,信号,定时事件。有两种高效的模式:Reactor和Proactor,同步的IO模式通常用来实现Reactor模式,异步IO模式通常用来实现Proactor模式。

Reactor:
要求主线程IO处理单元,只负责监听文件描述符上是否有事件发生,有的话就立即将该事件同时工作线程(也叫逻辑线程),将socket可读可写事件放入请求队列,交给工作线程处理。除此之外,主线程不做任何其他实质的事情。读写数据,业务处理均在工作线程完成。

使用同步IO(epoll_wait为例)实现的Reactor模式的工作流程是:

  • 主线程往epoll内核事件表中注册socket上的读就绪事件
  • 主线程调用epoll_wait等待socket上有数据可读
  • 当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket 可读事件放入请求队列
  • 睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件
  • 当逐项调用epoll_wait等待socket可写
  • 当socket可写时,epoll_wait通知主线程。主线程将socket可写事件放入请求队列
  • 睡眠在请求队列上的某个工作线程被唤醒,它往socket上写如服务器处理客户请求的结果

工作流程图:
在这里插入图片描述

4、解释一下阻塞,非阻塞,同步,异步的过程。

陈硕:在处理IO的时候,阻塞和非阻塞都是同步IO,只有使用特殊的API才是异步IO。

阻塞:调用某个函数,就等待这个函数的返回,必须有返回才能走下一步。

非阻塞:调用某个函数检测IO事件是否就绪,没有就绪就会返回-1,不会一直等待。

5、linux下的5种IO模型

阻塞,非阻塞,IO复用,信号驱动,异步

6、HTTP请求报文格式

在这里插入图片描述

GET / HTTP/1.1

Host: www.baidu.com

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8

Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip, deflate, br

Connection: keep-alive

Cookie: BAIDUID=6729CB682DADC2CF738F533E35162D98:FG=1; BIDUPSID=6729CB682DADC2CFE015A8099199557E; PSTM=1614320692; BD_UPN=13314752; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; __yjs_duid=1_d05d52b14af4a339210722080a668ec21614320694782; BD_HOME=1; H_PS_PSSID=33514_33257_33273_31660_33570_26350; BA_HECTOR=8h2001alag0lag85nk1g3hcm60q Upgrade-Insecure-Requests: 1

Cache-Control: max-age=0

7、HTTP相应报文格式

在这里插入图片描述

HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xf3c9743300024ee4
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 26 Feb 2021 08:44:35 GMT
Expires: Fri, 26 Feb 2021 08:44:35 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=13; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33514_33257_33273_31660_33570_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1614329075128412289017566699583927635684
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked

8、EPOLLONESHOT 事件

使用ET模式,一个socket上的某个事件还是可能触发多次,这在并发程序中就会引发一个问题。比如一个线程在读取完某个socket上的数据后开始处理这些数据,而在数据的处理过程中该socket上又有了新数据可读(EPOLLIN再次被触发)此时另外一个线程被唤醒来读取这些新数据。

简短来说,就是一个事件可能被两个不同线程去处理,这是不愿发生的。这就可以使用epolloneshot来处理。

对于注册了 EPOLLONESHOT 事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或者异 常事件,且只触发一次,除非我们使用 epoll_ctl 函数重置该文件描述符上注册的 EPOLLONESHOT 事 件。这样,当一个线程在处理某个 socket 时,其他线程是不可能有机会操作该 socket 的。但反过来思 考,注册了 EPOLLONESHOT 事件的 socket 一旦被某个线程处理完毕, 该线程就应该立即重置这个 socket 上的 EPOLLONESHOT 事件,以确保这个 socket 下一次可读时,其 EPOLLIN 事件能被触发,进 而让其他工作线程有机会继续处理这个 socket。

9、RAII机制

资源在对象构造初始化,资源在对象析构时释放。

在项目中的释放是放入连接池中。

让其他工作线程有机会继续处理这个 socket。

9、RAII机制

资源在对象构造初始化,资源在对象析构时释放。

在项目中的释放是放入连接池中。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值