web服务器

      epoll 是一个 I/O 多路复用模型,可以用一个进程去处理多个客户端,它是 select 和 poll 的增强版本(select 和 poll 是更早的多路复用模型)。

      epoll 使用一个文件描述符管理多个描述符,将用户关心的文件描述符存放到内核的一个事件表中,这样在用户空间和内核空间的 copy 只需一次。

      epoll 是基于事件驱动模型。

假设一个场景:有100万用户同时与一个进程保持着TCP连接,而每一时刻只有几十个或几百个TCP连接是活跃的,也就是每一时刻进程只能处理这100万连接中的一小部分连接。那么,如何高效的处理这种场景?进程是否在每次查询操作系统收集有事件发生的TCP连接时,把这100万个连接告诉操作系统,然后由操作系统找出其中有事件发生的几百个连接呢?实际上,在Linux2.4版本以前,select 或 poll 事件驱动方式是这样做的。

      这里有一个非常明显的问题,即在某一时刻,进程收集有事件的连接时,其实这100万连接中的大部分都是没有事件发生的。如果每次收集事件时,都把100万连接的套接字传给操作系统(这首先是用户态内存到核心态内存的大量复制),而由操作系统内核寻找这些连接上有没有未处理的事件,将会是巨大的资源浪费(select 和 poll 就是这样做的),因为它们最多只能处理几千个并发连接。而 epoll 不是这样的,它在 Linux 内核中申请了一个简易的文件系统,把原先的一个 select 或 poll 调用分成3部分:

int epoll_create(int size);  
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);  
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);  

(1)调用 epoll_create,建立一个 epoll 对象(在 epoll 文件系统中给中国句柄分配资源);

(2)调用epoll_ctl,向 epoll 对象中添加这100万个连接的套接字;

(3)调用epoll_wait,收集发生事件的连接。

      这样,只需要在进程启动时建立一个 epoll 对象,并在需要的时候向它添加或删除连接就可以了。因此,在实际收集事件时,epoll_wait 的效率就会非常高,因为调用epoll_wait 时并没有向它传递这100万个连接,内核也不需要去遍历全部的连接。

项目介绍

       本项目的主要目的是对浏览器(客户端)的链接请求进行解析处理,处理完之后给浏览器(客户端)返回一个响应,如文字、图片、视频等。也就是一次完整的HTTP请求的过程。

1. 基础知识

socket:用于客户端和服务器之间的通信如果多个客户端同时发出请求,想要连接服务器,那么服务器如何对这些客户端请求进行处理? ---- IO复用

IO复用:在单进程中通过记录跟踪每一个socket(I/O流)的状态,来同时管理多个I/O流。IO复用尽可能多的提高服务器的吞吐量。

      当多个客户端请求与服务器连接时,如何同时给每个客户端提供服务?首先要有一个队列来对多个连接请求进行排序存放,然后需要通过并发多线程的技术对已连接的客户端请求进行应答处理。本项目利用epoll I/O复用技术实现对监听socket(listenfd)和连接socket(客户端请求连接之后的socket)的同时监听。注意,I/O复用虽然可以同时监听多个文件描述符,但是它本身是阻塞的,所以为了提高效率,这部分通过线程池来实现并发,为每个就绪的文件描述符分配一个逻辑单元(线程)来处理。

    多线程:线程不需要操作系统为其分配资源,它的资源就在进程中,且线程的创建和销毁相比于进程小的多,所以多线程程序效率较高。在本项目中,频繁的创建和销毁线程是不可取的,故引入线程池技术。即,提前创建一批线程,当有任务要执行时,从线程池中选一个线程来执行任务,任务执行完毕,再将其放入线程池,以等待后序任务。

事件处理模式:

(1)Reactor模式:主线程只负责监听文件描述符上是否有事件发生(可读、可写),若有,则立即通知工作线程,将socket可读可写事件放入请求队列,读写数据、接受新连接及处理客户端请求均在工作线程中完成。

(2)Proactor模式:主线程和内核负责处理读写数据、接受新连接等I/O操作,工作线程仅负责业务逻辑,如处理客户端请求。

2. 项目细节

      服务器后端的处理方式是使用socket通信,利用多路IO复用模型来同时处理多个客户端的请求,使用预先构建好的线程池中的线程来解析客户端请求,(对于到来的IO事件)使用Reactor模式,主线程负责监听IO,获取IO请求后把请求对象放入请求队列,交给工作线程。睡眠在请求队列中的工作线程被唤醒进行数据读取及逻辑处理。利用状态机思想解析HTTP报文,支持GET/POST请求,支持长/短连接。最后利用webbench进行了服务器并发量测试,至少可以满足上万的并发连接。

使用基于小根堆的定时器关闭超时请求,解决超时,连接系统资源占用的问题。

Reactor 模式:

      主线程中,epoll 监听套接字,处理已就绪套接字上的 IO 请求,包括已就绪连接的写请求、新的客户端连接请求等;将就绪IO套接字上的请求封装成一个requestData对象,这个对象里面包含了处理函数、就绪文件描述符等等;然后把requestData对象交给请求队列,然后工作线程会在请求队列里面取任务,并利用requestData对象中的处理函数来分析请求,发送一个响应。

webbench原理:

      webbeach 是一款轻量级的网址压力测试工具,可以实现3万+的并发测试。父进程fork若干个子进程,每个子进程在用户要求时间内或默认时间内对目标 web 循环发出访问请求,父子进程通过管道进行通信,子进程通过管道写端向父进程传递在若干次请求访问完毕后记录到的总信息,父进程通过管道读端读取子进程发来的相关信息,子进程在时间到后结束,父进程在所有子进程退出后统计并给用户显示最后的测试结果,然后退出。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值