文章目录
一、服务器基本框架
服务器基本框架主要由I/O处理单元,逻辑单元和网络存储单元组成,其中每个单元之间通过请求队列进行通信,从而协同完成任务。
模块 | 功能 |
---|---|
I/O处理单元 | 处理客户端连接,读写网络数据。 |
逻辑单元 | 处理业务逻辑。 |
网络存储单元 | 本地数据库和文件等。 |
二、IO模型
三、两种高效的事件处理模式
1. Reactor模式
- 主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,有的话立即通知工作线程(逻辑单元),读写数据、接受新连接及处理客户请求均在工作线程中完成。通常由同步I/O实现。
2. Proactor模式
- 主线程(I/O处理单元)和内核负责处理读写数据、接受新连接等I/O操作,工作线程(逻辑单元)仅负责业务逻辑,如处理客户请求。通常由异步I/O实现。
四、并发编程模式 – 半同步/半异步模式
- 同步线程用于处理客户逻辑,异步线程用于处理I/O事件。
- 异步线程监听到客户请求后,就将其封装成请求对象并插入请求队列中。
- 请求队列将通知在同步模式下工作线程来读取并处理该请求对象。
五、IO多路复用
补充:一个线程读取某个Socket上的数据后开始处理数据,在处理过程中该Socket上又有新数据可读,另一个线程被唤醒读取,此时出现两个线程处理同一个Socket。我们期望一个Socket连接在任一时刻都只被一个线程处理,通过对该文件描述符注册EPOLLONESHOT
事件,令一个线程处理socket时,其他线程将无法处理。当该线程处理完后,需要重置EPOLLONESHOT
事件。
六、代码实现
1.webserver.h
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <cassert>
#include <sys/epoll.h>
#include "./threadpool/threadpool.h"
#include "./http/http_conn.h"
// 最大文件描述符
const int MAX_FD = 65536;
// 最大事件数
const int MAX_EVENT_NUMBER = 10000;
// 最小超时单位
const int TIMESLOT = 5;
class WebServer
{
public:
// 构造函数
WebServer();
// 析构函数
~WebServer();
// 初始化部分成员属性
void init(int port, string user, string passWord, string databaseName,
int log_write, int opt_linger, int trigmode, int sql_num,
int thread_num, int close_log, int actor_model);
void thread_pool();
void sql_pool();
void log_write();
// 设置监听与通信文件描述符触发模式
void trig_mode();
void eventListen();
void eventLoop();
void timer(int connfd, struct sockaddr_in client_address);
void adjust_timer(util_timer *timer);
void deal_timer(util_timer *timer, int sockfd);
bool dealclinetdata();
bool dealwithsignal(bool &timeout, bool &stop_server);
void dealwithread(int sockfd);
void dealwithwrite(int sockfd);
public:
/******基础******/
// 服务器端口
int m_port;
// root文件夹的路径
char *m_root;
// 日志写入方式
int m_log_write;
// 是否关闭日志
int m_close_log;
// 并发模型选择
int m_actormodel;
int m_pipefd[2];
int m_epollfd;
// HTTP对象数组指针
http_conn *users;
/******数据库相关******/
// 数据库连接池对象
connection_pool *m_connPool;
// 登录数据库用户名
string m_user;
// 登录数据库密码
string m_passWord;
// 使用数据库名
string m_databaseName;
// 数据库连接池数量
int m_sql_num;
/******线程池相关******/
// 线程池对象
threadpool<http_conn> *m_pool;
// 线程池内的线程数量
int m_thread_num;
/******epoll_event相关******/
// 结构体数组,存储已就绪的文件描述符的信息
epoll_event events[MAX_EVENT_NUMBER];
// 监听文件描述符
int m_listenfd;
// 是否优雅关闭连接
int m_OPT_LINGER;
// 触发组合模式
int m_TRIGMode;
// 监听文件描述符触发方式
int m_LISTENTrigmode;
// 通信文件描述符触发方式
int m_CONNTrigmode;
/******定时器相关******/
// 连接资源对象数组指针
client_data *users_timer;
Utils utils;
};
#endif
2.webserver.cpp
#include "webserver.h"
// 构造函数
WebServer::WebServer()
{
// 创建MAX_FD个HTTP对象
this->users = new http_conn[MAX_FD];
// 当前工作目录的绝对路径
char server_path[200];
getcwd(server_path, 200);
char root[6] = "/root";
// 网站资源文件夹的路径
this->m_root = (char *)malloc(strlen(server_path) + strlen(root) + 1);
strcpy(this->m_root, server_path);
strcat(this->m_root, root);
// 创建MAX_FD个连接资源对象
this->users_timer = new