WebServer项目——webserver详解
WebServer项目——webserver详解
webserver介绍
这个webserver类是对整个web服务器的抽象,基于HTTPconnection类、timer类、epoller类、threadpool类实现一个完整的高性能web服务器的所有功能。
需要满足的功能有:
- 初始化服务器,为HTTP的连接做好准备;
- 处理每一个HTTP连接;
- 用定时器给每一个HTTP连接定时,并且处理掉过期的连接;
- 运用IO多路复用技术提升IO性能;
- 运用线程池技术提升服务器性能;
webserver的逻辑
首先是进行服务器的初始化,进行各种参数设置。其中包括了事件模式的初始化、socket连接的建立过程,主要用到了以下两个函数:
1 | bool initSocket_(); |
在初始化socket的过程中,将listenFd_描述符也加入epoll进行监视。这样的话,当监听的listenFd(socketFd)有新连接的时候,就会发来一个可读信号。同时,也将监听socket的行为(是否有新的连接)和监听每一个HTTP连接的行为(已经建立的连接有无IO请求)统一起来了,都抽象为了读写两个操作。所以我们就可以每一次直接处理所有的epoll就绪事件,在过程中对有新连接请求的情况单独分出来处理就可以了。
接下来开始处理HTTP连接。
最开始当然先清理过期的连接,并且得到下一次处理的时间。这个首先就需要在这个类中有一个TimerManager类型指针或者对象,用它调用getNextHandle()
函数:
1 | timeMS=timer_->getNextHandle(); |
然后得到所有已经就绪的事件,用一个循环处理所有的epoll就绪事件。在过程中需要分两种类型:收到新的HTTP请求和其他的读写请求。
- 收到新的HTTP请求的情况
在fd==listenFd_
的时候,也就是收到新的HTTP请求的时候,需要调用函数:
1 | void handleListen_(); |
这个函数中会得到新的描述符,然后需要将新的描述符和新的描述符对应的连接记录下来,调用下述函数即可:
1 | void addClientConnection(int fd, sockaddr_in addr); |
- 已经建立连接的HTTP发来IO请求的情况
这种情况下,必然需要提供读写的处理,用下述两个函数完成:
1 | void handleWrite_(HTTPconnection* client); |
但是为了提高性能,使用了线程池,所以这两个函数就是将读写的底层实现函数加入到线程池,两个读写的底层实现函数为:
1 | void onRead_(HTTPconnection* client); |
epoll使用的是边缘触发ET,所以在读结束的时候根据需要改变epoll的事件。
边缘触发
1. 对于读操作
(1)当缓冲区由不可读变为可读的时候,即缓冲区由空变为不空的时候。
(2)当有新数据到达时,即缓冲区中的待读数据变多的时候。
(3)当缓冲区有数据可读,且应用进程对相应的描述符进行EPOLL_CTL_MOD
修改EPOLLIN
事件时。
2. 对于写操作
(1)当缓冲区由不可写变为可写时。
(2)当有旧数据被发送走,即缓冲区中的内容变少的时候。
(3)当缓冲区有空间可写,且应用进程对相应的描述符进行EPOLL_CTL_MOD
修改EPOLLOUT
事件时。
用函数:
1 | void onProcess_(HTTPconnection* client); |
来完成。
当一切都完成的时候,还需要一个关闭服务器的函数:
1 | void closeConn_(HTTPconnection* client); |
WebServer的实现
1 | class WebServer { |