前言
项目简介:
Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.
- 使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现) 的并发模型
- 使用状态机解析HTTP请求报文,支持解析GET和POST请求
- 访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件
- 实现同步/异步日志系统,记录服务器运行状态
- 经Webbench压力测试可以实现上万的并发连接数据交换
sql_connection.cpp用于实现数据库的连接池。主要内容如下:
1.数据库连接池
- 单例模式,保证唯一
- list实现连接池
- 连接池为静态大小
- 互斥锁实现线程安全
2.校验
- HTTP请求采用POST方式
- 登录用户名和密码校验
- 用户注册及多线程注册安全
原项目地址的注释较少不适合初学者,于是我将每行都加上了注释帮助大家更好的理解:
cpp
#include <mysql/mysql.h> // 包含 MySQL 库,用于和 MySQL 数据库交互
#include <stdio.h> // 标准输入输出库
#include <string> // C++ 字符串库
#include <string.h> // C 字符串处理库
#include <stdlib.h> // 标准库,包含内存分配、进程控制等
#include <list> // C++ STL 的 list 容器,用于存储 MySQL 连接
#include <pthread.h> // 线程库,用于多线程同步
#include <iostream> // C++ 标准输入输出流
#include "sql_connection_pool.h" // 连接池头文件
using namespace std; // 使用标准命名空间
// 构造函数,初始化成员变量
connection_pool::connection_pool()
{
m_CurConn = 0; // 当前已使用的连接数
m_FreeConn = 0; // 当前空闲的连接数
}
// 获取连接池实例(单例模式)避免重复创建连接池对象,进而管理和复用 MySQL 连接。
connection_pool *connection_pool::GetInstance()
{
static connection_pool connPool; // 静态实例,保证全局唯一
return &connPool; // 返回连接池的指针
}
// 构造初始化函数,设置连接池的相关配置
void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, int MaxConn, int close_log)
{
// 保存数据库连接的参数
m_url = url; // 数据库主机地址
m_Port = Port; // 端口号
m_User = User; // 数据库用户名
m_PassWord = PassWord; // 数据库密码
m_DatabaseName = DBName; // 数据库名
m_close_log = close_log; // 是否关闭日志
// 创建最大连接数个 MySQL 连接并加入连接池
for (int i = 0; i < MaxConn; i++)
{
MYSQL *con = NULL;
con = mysql_init(con); // 初始化 MySQL 连接
if (con == NULL) // 如果初始化失败,打印错误日志并退出程序
{
LOG_ERROR("MySQL Error");
exit(1);
}
// 连接到 MySQL 数据库
con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);
if (con == NULL) // 如果连接失败,打印错误日志并退出程序
{
LOG_ERROR("MySQL Error");
exit(1);
}
// 将成功连接的 MySQL 连接加入连接池列表
connList.push_back(con);
++m_FreeConn; // 增加空闲连接数
}
// 初始化信号量,用于控制连接的获取和释放
reserve = sem(m_FreeConn);
m_MaxConn = m_FreeConn; // 设置最大连接数
}
// 从连接池中获取一个可用的 MySQL 连接
MYSQL *connection_pool::GetConnection()
{
MYSQL *con = NULL;
if (0 == connList.size()) // 如果连接池为空,返回 NULL
return NULL;
reserve.wait(); // 等待信号量,如果没有空闲连接则等待
lock.lock(); // 加锁,防止多线程同时操作连接池
// 从连接池中取出一个连接
con = connList.front();
connList.pop_front(); // 移除最前面的连接
--m_FreeConn; // 空闲连接数减少
++m_CurConn; // 使用中的连接数增加
lock.unlock(); // 解锁
return con; // 返回获取的连接
}
// 释放当前使用的 MySQL 连接,将其放回连接池
bool connection_pool::ReleaseConnection(MYSQL *con)
{
if (NULL == con) // 如果连接为空,返回 false
return false;
lock.lock(); // 加锁,防止多线程同时操作连接池
// 将连接放回连接池
connList.push_back(con);
++m_FreeConn; // 空闲连接数增加
--m_CurConn; // 使用中的连接数减少
lock.unlock(); // 解锁
reserve.post(); // 释放信号量,通知等待的线程有连接可用
return true;
}
// 销毁连接池,关闭所有 MySQL 连接
void connection_pool::DestroyPool()
{
lock.lock(); // 加锁,防止其他线程操作连接池
if (connList.size() > 0)
{
// 遍历连接池中的所有连接,逐一关闭
list<MYSQL *>::iterator it;
for (it = connList.begin(); it != connList.end(); ++it)
{
MYSQL *con = *it;
mysql_close(con); // 关闭 MySQL 连接
}
m_CurConn = 0; // 重置已使用连接数
m_FreeConn = 0; // 重置空闲连接数
connList.clear(); // 清空连接池列表
}
lock.unlock(); // 解锁
}
// 返回当前空闲的连接数
int connection_pool::GetFreeConn()
{
return this->m_FreeConn; // 返回空闲连接数
}
// 析构函数,销毁连接池,释放所有连接
connection_pool::~connection_pool()
{
DestroyPool(); // 调用销毁连接池的函数
}
// RAII 机制,自动管理 MySQL 连接的获取和释放
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool){
*SQL = connPool->GetConnection(); // 获取一个数据库连接并赋值给传入的指针
conRAII = *SQL; // 保存获取到的连接
poolRAII = connPool; // 保存连接池的引用
}
// 析构函数,自动释放连接回连接池
connectionRAII::~connectionRAII(){
poolRAII->ReleaseConnection(conRAII); // 将连接放回连接池
}