Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请求merger #35

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions CGImysql/sql_connection_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ void connection_pool::init(string url, string User, string PassWord, string DBNa
m_MaxConn = m_FreeConn;
}


//当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{
Expand All @@ -68,7 +67,7 @@ MYSQL *connection_pool::GetConnection()
return NULL;

reserve.wait();

lock.lock();

con = connList.front();
Expand Down Expand Up @@ -131,13 +130,15 @@ connection_pool::~connection_pool()
DestroyPool();
}

connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool){
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool)
{
*SQL = connPool->GetConnection();

conRAII = *SQL;
poolRAII = connPool;
}

connectionRAII::~connectionRAII(){
connectionRAII::~connectionRAII()
{
poolRAII->ReleaseConnection(conRAII);
}
45 changes: 35 additions & 10 deletions CGImysql/sql_connection_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@

using namespace std;

/*
* m_MaxConn 最大连接数
m_CurConn 当前已使用的连接数
m_FreeConn 当前空闲的连接数
connList 连接池
* m_url 主机地址
m_Port 数据库端口号
m_User 登陆数据库用户名
m_PassWord 登陆数据库密码
m_DatabaseName 使用数据库名
int m_close_log 日志开关
* 单例模式:将构造写入private,通过指针进行实例化,这样保证只能实例化一次
* 懒汉模式:需要用到创建实例了程序再去创建实例
* GetConnection 获取数据库连接,从连接池中返回一个可用连接
ReleaseConnection 回收连接,将连接放回连接池中
GetFreeConn 获取当前连接池中空闲(可用)的连接数
DestroyPool 释放连接池,即释放所有连接
GetInstance 懒汉模式+单例模式
init 实例化后真正的构造函数
*/
class connection_pool
{
public:
Expand All @@ -24,34 +44,39 @@ class connection_pool
//单例模式
static connection_pool *GetInstance();

void init(string url, string User, string PassWord, string DataBaseName, int Port, int MaxConn, int close_log);
void init(string url, string User, string PassWord, string DataBaseName, int Port, int MaxConn, int close_log);

private:
connection_pool();
~connection_pool();

int m_MaxConn; //最大连接数
int m_CurConn; //当前已使用的连接数
int m_MaxConn; //最大连接数
int m_CurConn; //当前已使用的连接数
int m_FreeConn; //当前空闲的连接数
locker lock;
list<MYSQL *> connList; //连接池
sem reserve;

public:
string m_url; //主机地址
string m_Port; //数据库端口号
string m_User; //登陆数据库用户名
string m_PassWord; //登陆数据库密码
string m_url; //主机地址
string m_Port; //数据库端口号
string m_User; //登陆数据库用户名
string m_PassWord; //登陆数据库密码
string m_DatabaseName; //使用数据库名
int m_close_log; //日志开关
int m_close_log; //日志开关
};

class connectionRAII{
/*
* 采用RAII封装数据库连接池
* RAII:是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源
*/
class connectionRAII
{

public:
connectionRAII(MYSQL **con, connection_pool *connPool);
~connectionRAII();

private:
MYSQL *conRAII;
connection_pool *poolRAII;
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ TinyWebServer
===============
Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.

* [测试页](http://175.24.234.48:9007)
* 使用 **线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现)** 的并发模型
* 使用**状态机**解析HTTP请求报文,支持解析**GET和POST**请求
* 访问服务器数据库实现web端用户**注册、登录**功能,可以请求服务器**图片和视频文件**
Expand Down Expand Up @@ -119,6 +120,7 @@ Demo演示
* 服务器测试环境
* Ubuntu版本16.04
* MySQL版本5.7.29
* Centos 7 + MYSQL 8.0.22
* 浏览器测试环境
* Windows、Linux均可
* Chrome
Expand Down Expand Up @@ -245,4 +247,4 @@ CPP11实现
------------
Linux高性能服务器编程,游双著.

感谢以下朋友的PR和帮助: [@RownH](https://github.com/RownH),[@mapleFU](https://github.com/mapleFU),[@ZWiley](https://github.com/ZWiley),[@zjuHong](https://github.com/zjuHong),[@mamil](https://github.com/mamil),[@byfate](https://github.com/byfate),[@MaJun827](https://github.com/MaJun827),[@BBLiu-coder](https://github.com/BBLiu-coder),[@smoky96](https://github.com/smoky96),[@yfBong](https://github.com/yfBong),[@liuwuyao](https://github.com/liuwuyao),[@Huixxi](https://github.com/Huixxi),[@markparticle](https://github.com/markparticle).
感谢以下朋友的PR和帮助: [@RownH](https://github.com/RownH),[@mapleFU](https://github.com/mapleFU),[@ZWiley](https://github.com/ZWiley),[@zjuHong](https://github.com/zjuHong),[@mamil](https://github.com/mamil),[@byfate](https://github.com/byfate),[@MaJun827](https://github.com/MaJun827),[@BBLiu-coder](https://github.com/BBLiu-coder),[@smoky96](https://github.com/smoky96),[@yfBong](https://github.com/yfBong),[@liuwuyao](https://github.com/liuwuyao),[@Huixxi](https://github.com/Huixxi),[@markparticle](https://github.com/markparticle),[@Zhenghao-Liu](https://github.com/Zhenghao-Liu)。
9 changes: 6 additions & 3 deletions config.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "config.h"
#include <stdlib.h>

Config::Config(){
Config::Config()
{
//端口号,默认9006
PORT = 9006;

Expand Down Expand Up @@ -32,7 +34,8 @@ Config::Config(){
actor_model = 0;
}

void Config::parse_arg(int argc, char*argv[]){
void Config::parse_arg(int argc, char *argv[])
{
int opt;
const char *str = "p:l:m:o:s:t:c:a:";
while ((opt = getopt(argc, argv, str)) != -1)
Expand Down Expand Up @@ -80,7 +83,7 @@ void Config::parse_arg(int argc, char*argv[]){
break;
}
default:
break;
exit(EXIT_FAILURE);
}
}
}
2 changes: 1 addition & 1 deletion config.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Config
Config();
~Config(){};

void parse_arg(int argc, char*argv[]);
void parse_arg(int argc, char *argv[]);

//端口号
int PORT;
Expand Down
101 changes: 98 additions & 3 deletions http/http_conn.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,102 @@
#include "../timer/lst_timer.h"
#include "../log/log.h"

/*
* 线程池的工作类型类
* FILENAME_LEN 文件名的最大长度
READ_BUFFER_SIZE 度缓冲区的大小
WRITE_BUFFER_SIZE 写缓冲区的大小
METHOD HTTP请求方法
GET 申请获取资源
POST 客户端向服务器提交数据的方法
HEAD 要求服务器返回头部信息
PUT 上传某个资源
DELETE 删除某个资源
TRACE 要求目标服务器返回原始HTTP请求的内容
OPTIONS 查看服务器对某个特定URL都支持哪些请求方法
CONNECT 用于某些代理服务器,能把请求的连接转化为一个安全隧道
PATCH 对某个资源做部分修改
CHECK_STATE 解析客户请求时,主状态机所处的状态
CHECK_STATE_REQUESTLINE 分析请求行
CHECK_STATE_HEADER 分析头部域
CHECK_STATE_CONTENT 分析消息体
HTTP_CODE 服务器处理HTTP请求可能的结果
NO_REQUEST 请求不完整,需要继续读取数据
GET_REQUEST 获得了一个完整的客户请求
BAD_REQUEST 客户请求有语法错误
NO_RESOURCE 没有对应的资源
FORBIDDEN_REQUEST 客户对资源没有足够访问权限
FILE_REQUEST 客户请求是一个可读的文件
INTERAL_ERROR 服务器内部错误
CLOSED_CONNECTION 客户端已经关闭连接
LINE_STATUS 行的读取状态
LINE_OK 读取到一个完整的行
LINE_BAD 行出错
LINE_OPEN 行数据尚且不完整
* init 初始化接受新的连接
close_conn 关闭连接
process 处理客户请求
read_once 循环读取客户数据,知道无数据刻度或对方关闭连接
write 非阻塞写入数据
get_address 返回服务器端通信的socket地址
initmysql_result 初始化mysql连接,取出数据库保存的账号和密码,存入map中
timer_flag 是否开启了定时器
improv
* init 初始化连接
process_read 解析HTTP请求
以下一组函数被process_read调用以分析HTTP请求
parse_request_line 解析http请求行,获得请求方法,目标url及http版本号
parse_headers 解析http请求的一个头部信息
parse_content 判断http请求是否被完整读入,读完消息体,这里实质上没有真正解析消息体
do_request 当得到一个完整、正确的HTTP请求时,分析用户的请求内容:登陆、注册、获取文件
get_line 移动指针读取一行
parse_line 从状态机,用于分析出一行内容
process_write 填充HTTP应答
以下一组函数被process_write调用用以填充HTTP应答
unmap 释放共享内存映射区
add_response 往HTTP应答中写入待发送的数据
add_content 往HTTP应答写入消息体
add_status_line 往HTTP应答写入状态行
add_content_type 往HTTP应答写入头部字段的目标文档的MIME类型
add_content_length 往HTTP应答写入头部字段的目标文档的长度
add_linger 往HTTP应答写入头部字段的此次通信后是否关闭TCP连接
add_blank_line 往HTTP应答写入一个空行 \r\n
* m_pollfd epoll的事件表文件描述符
m_user_count 统计用户数量
mysql 连接的数据库
m_state 读为0,写为1
* m_sockfd HTTP连接的socket文件描述符
m_address HTTP对方的socket地址
m_read_buf 读缓冲区
m_read_idx 表示读缓冲中已经读入的客户数据的最后一个字节的下一个位置
m_check_idx 当前正在分析的字符在读缓冲区中的位置
m_start_line 当前正在解析的行的起始位置
m_write_buf 写缓冲区
m_write_idx 写缓冲区中待发送的字节数
m_check_state 主状态机当前所处的状态
m_method 请求方法
m_real_file 客户请求的目标文件的完整路径,其内容等于网站根目录doc_root+m_url
m_url 客户请求的目标文件的文件名
m_version HTTP 协议版本号,此程序只支持HTTP/1.1
m_host 主机名
m_content_length HTTP请求的消息体的长度
m_linger HTTP其你去是否要求保持连接
m_file_address 客户请求的目标文件被mmap到内存中的起始位置
m_file_stat 目标文件的状态:是否存在、是否为目录、是否刻度、文件信息
m_iv 采用writev写操作的内存分块
m_iv_count 采用writev写操作的内存分块数量
cgi 是否启用新的POST
m_string 存储请求头数据
bytes_to_send 需要发送的字节数
bytes_have_send 已经发送的字节数
doc_root 服务器端网站根目录
m_users 客户账号和密码
m_TRIGMode 是否采用ET工作模式
m_close_log 是否关闭日志功能
sql_uesr MYSQL用户名
sql_passwd MYSQL密码
sql_name MYSQL数据库名
*/
class http_conn
{
public:
Expand All @@ -42,7 +138,7 @@ class http_conn
TRACE,
OPTIONS,
CONNECT,
PATH
PATCH
};
enum CHECK_STATE
{
Expand Down Expand Up @@ -86,7 +182,6 @@ class http_conn
int timer_flag;
int improv;


private:
void init();
HTTP_CODE process_read();
Expand All @@ -111,7 +206,7 @@ class http_conn
static int m_epollfd;
static int m_user_count;
MYSQL *mysql;
int m_state; //读为0, 写为1
int m_state; //读为0, 写为1

private:
int m_sockfd;
Expand Down
36 changes: 36 additions & 0 deletions lock/locker.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
#include <pthread.h>
#include <semaphore.h>

/*
* 封装信号量的类
* sem_init函数用于初始化一个未命名的信号量
* sem_destory函数用于销毁信号量
* sem_wait函数将以原子操作方式将信号量减一,信号量为0时,sem_wait阻塞
* sem_post函数以原子操作方式将信号量加一,信号量大于0时,唤醒调用sem_post的线程
*/
class sem
{
public:
Expand Down Expand Up @@ -38,6 +45,14 @@ class sem
private:
sem_t m_sem;
};

/*
* 封装互斥锁的类
* pthread_mutex_init函数用于初始化互斥锁
* pthread_mutex_destory函数用于销毁互斥锁
* pthread_mutex_lock函数以原子操作方式给互斥锁加锁
* pthread_mutex_unlock函数以原子操作方式给互斥锁解锁
*/
class locker
{
public:
Expand Down Expand Up @@ -68,6 +83,19 @@ class locker
private:
pthread_mutex_t m_mutex;
};

/*
* 封装条件变量的类,此类与书本上的实现有所不同
* 与条件变量协作的互斥锁不是封装在类里,而是以参数形式传入
* pthread_cond_init函数用于初始化条件变量
* pthread_cond_destory函数销毁条件变量
* pthread_cond_wait函数用于等待目标条件变量.该函数调用时需要传入 mutex参数(必须是一个已经加锁的互斥锁),
函数执行时,先把调用线程放入条件变量的请求队列,然后将互斥锁mutex解锁,当函数成功返回为0时,互斥锁会再次被锁上.
也就是说函数内部会有一次解锁和加锁操作.
* pthread_cond_broadcast函数以广播的方式唤醒所有等待目标条件变量的线程
* pthread_cond_signal函数用于唤醒一个等待目标条件变量的线程,
至于哪个线程被唤醒,则取决于线程的优先级和调度策略
*/
class cond
{
public:
Expand All @@ -83,6 +111,14 @@ class cond
{
pthread_cond_destroy(&m_cond);
}
/*
* 参数m_mutex必须是一个已经上锁的互斥变量
* 如果m_mutex的type是一个PTHREAD_MUTEX_NORMAL普通锁
可以通过pthread_mutex_trylock的方式判断返回值来检测原先是否已经加锁
别忘了如果trylock成功要记得解锁
* 但是涉及到pthread_mutex_t的属性type还有别的类型的锁
* 只能将安全性结果交给函数外保证
*/
bool wait(pthread_mutex_t *m_mutex)
{
int ret = 0;
Expand Down
Loading