240717班级,工业化控制系统,煤矿相关行业,昆仑系统
lzx
2024-10-29 b887f7dda2716aa86980167a1b4b72d187ffb9ef
Merge branch 'master' of ssh://115.28.86.8:29418/~admin/昆仑_1025
1 文件已重命名
10个文件已修改
15个文件已添加
3个文件已删除
809 ■■■■■ 已修改文件
Client/冀浩昶/document/生产计划管理_需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/刘子航/document/昆仑_警报管理.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/姜可庚/document/权限管理需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/朱航/document/朱航.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/朱航/document/需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/申烜/document/注册登录需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/郑凯文/document/About version updates.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/郑凯文/document/About version updates(第二版).docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/黎弘霖/document/设备管理需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/龚启祥/document/昆仑_大屏显示.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/李转转/document/需求分析报告.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/单例模式封装.txt 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/备份导出.txt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库模块需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库连接.txt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库连接池类.txt 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/防注入.txt 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/.vscode/c_cpp_properties.json 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/.vscode/launch.json 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/.vscode/settings.json 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/README.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/block_queue.h 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/log.cpp 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/code/log/log.h 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/马丽萍/document/日志需求分析文档.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/马渝杭/document/版本更新功能需求_server.docx 补丁 | 查看 | 原始文档 | blame | 历史
参考文档/需求分析模板/~$求功能规格说明书_2.docx 补丁 | 查看 | 原始文档 | blame | 历史
日志需求分析文档.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/¼½ºÆêÆ/document/Éú²ú¼Æ»®¹ÜÀí_ÐèÇó·ÖÎö.docx
Binary files differ
Client/Áõ×Óº½/document/À¥ÂØ_¾¯±¨¹ÜÀí.docx
Binary files differ
Client/½ª¿É¸ý/document/ȨÏÞ¹ÜÀíÐèÇó·ÖÎö.docx
Binary files differ
Client/Ö캽/document/Ö캽.docx
Binary files differ
Client/Ö캽/document/ÐèÇó·ÖÎö.docx
Binary files differ
Client/ÉêŸ@/document/×¢²áµÇ¼ÐèÇó·ÖÎö.docx
Binary files differ
Client/Ö£¿­ÎÄ/document/About version updates.docx
Binary files differ
Client/Ö£¿­ÎÄ/document/About version updates£¨µÚ¶þ°æ£©.docx
Binary files differ
Client/ÀèºëÁØ/document/É豸¹ÜÀíÐèÇó·ÖÎö.docx
Binary files differ
Client/¹¨ÆôÏé/document/À¥ÂØ_´óÆÁÏÔʾ.docx
Binary files differ
Server/Àîתת/document/ÐèÇó·ÖÎö±¨¸æ.docx
Binary files differ
Server/ÍõçûÔª/document/µ¥Àýģʽ·â×°.txt
New file
@@ -0,0 +1,51 @@
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
class DatabaseOperator {
private:
    // ç§æœ‰æž„造函数
    DatabaseOperator() {
        try {
            driver = sql::mysql::get_mysql_driver_instance();
            connection = driver->connect("tcp://127.0.0.1:3306", "username", "password");
            connection->setSchema("your_database");
        } catch (sql::SQLException &e) {
            std::cerr << "数据库连接错误: " << e.what() << std::endl;
        }
    }
    static DatabaseOperator* instance;
    static std::mutex mutex;
    sql::Driver* driver;
    std::unique_ptr<sql::Connection> connection;
public:
    // èŽ·å–å•ä¾‹å®žä¾‹
    static DatabaseOperator* getInstance() {
        std::lock_guard<std::mutex> lock(mutex);
        if (instance == nullptr) {
            instance = new DatabaseOperator();
        }
        return instance;
    }
    // æ‰§è¡ŒæŸ¥è¯¢æ“ä½œï¼ˆç¤ºä¾‹ï¼‰
    sql::ResultSet* query(const std::string& sql) {
        try {
            std::unique_ptr<sql::Statement> stmt(connection->createStatement());
            return stmt->executeQuery(sql);
        } catch (sql::SQLException &e) {
            std::cerr << "查询错误: " << e.what() << std::endl;
        }
        return nullptr;
    }
};
std::mutex DatabaseOperator::mutex;
DatabaseOperator* DatabaseOperator::instance = nullptr;
Server/ÍõçûÔª/document/±¸·Ýµ¼³ö.txt
New file
@@ -0,0 +1,29 @@
#!/bin/bash
# æ•°æ®åº“连接参数
DB_USER="your_username"
DB_PASS="your_password"
DB_NAME="your_database_name"
BACKUP_DIR="/path/to/backup/directory"
# èŽ·å–å½“å‰æ—¥æœŸï¼Œç”¨äºŽæ–‡ä»¶å
DATE=$(date +%Y%m%d%H%M%S)
# å¤‡ä»½æ–‡ä»¶å
BACKUP_FILE="${BACKUP_DIR}/backup_${DATE}.sql"
# åˆ›å»ºå¤‡ä»½ç›®å½•(如果不存在)
mkdir -p $BACKUP_DIR
# ä½¿ç”¨mysqldump进行数据库备份
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME > $BACKUP_FILE
if [ $? -eq 0 ]; then
    echo "数据库备份成功:$BACKUP_FILE"
else
    echo "数据库备份失败"
fi
# æ·»åŠ å®šæ—¶ä»»åŠ¡ï¼ˆä½¿ç”¨crontab -e来编辑定时任务)
# ä¾‹å¦‚,每天凌晨2点执行备份
# 0 2 * * * /path/to/this/script.sh
Server/ÍõçûÔª/document/Êý¾Ý¿â.docx
Binary files differ
Server/ÍõçûÔª/document/Êý¾Ý¿âÄ£¿éÐèÇó·ÖÎö.docx
Binary files differ
Server/ÍõçûÔª/document/Êý¾Ý¿âÁ¬½Ó.txt
New file
@@ -0,0 +1,16 @@
#include "MySQL.h"
#include <WinSock2.h>
#include <mysql.h>
#include <iostream>
#include <string>
using namespace std;
int main() {
    MYSQL mysql;
    mysql_init(&mysql);//初始化
    //连接数据库服务器服务器      IP               ç”¨æˆ·å    å¯†ç       æ•°æ®åº“端口号
    mysql_real_connect(&mysql, "192.168.136.128", "root", "123456", "wang", 3306, NULL, 0);
    string sql="set names gbk";
    mysql_real_query(&mysql, sql.c_str(), sql.size());
        mysql_close(&mysql);
    return 0;
Server/ÍõçûÔª/document/Êý¾Ý¿âÁ¬½Ó³ØÀà.txt
New file
@@ -0,0 +1,91 @@
#include <iostream>
#include <list>
#include <mutex>
#include <condition_variable>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
class SQLConnectionPool {
private:
    SQLConnectionPool(int minConns, int maxConns) :
        minConnections(minConns), maxConnections(maxConns), currentConnections(0) {}
    static SQLConnectionPool* instance;
    static std::mutex mutex;
    std::condition_variable cv;
    int minConnections;
    int maxConnections;
    int currentConnections;
    std::list<std::unique_ptr<sql::Connection>> connections;
    // åˆ›å»ºä¸€ä¸ªæ–°çš„æ•°æ®åº“连接
    std::unique_ptr<sql::Connection> createConnection() {
        try {
            sql::Driver* driver = sql::mysql::get_mysql_driver_instance();
            std::unique_ptr<sql::Connection> conn(driver->connect("tcp://127.0.0.1:3306", "username", "password"));
            conn->setSchema("your_database");
            return conn;
        } catch (sql::SQLException &e) {
            std::cerr << "创建连接错误: " << e.what() << std::endl;
            return nullptr;
        }
    }
public:
    // èŽ·å–å•ä¾‹å®žä¾‹
    static SQLConnectionPool* getInstance(int minConns, int maxConns) {
        std::lock_guard<std::mutex> lock(mutex);
        if (instance == nullptr) {
            instance = new SQLConnectionPool(minConns, maxConns);
            instance->initializePool();
        }
        return instance;
    }
    // åˆå§‹åŒ–连接池
    void initializePool() {
        for (int i = 0; i < minConnections; ++i) {
            std::unique_ptr<sql::Connection> conn = createConnection();
            if (conn) {
                connections.push_back(std::move(conn));
                currentConnections++;
            }
        }
    }
    // èŽ·å–æ•°æ®åº“è¿žæŽ¥
    std::unique_ptr<sql::Connection> getConnection() {
        std::unique_lock<std::mutex> lock(mutex);
        while (connections.empty() && currentConnections >= maxConnections) {
            cv.wait(lock);
        }
        std::unique_ptr<sql::Connection> conn;
        if (!connections.empty()) {
            conn = std::move(connections.front());
            connections.pop_front();
        } else if (currentConnections < maxConnections) {
            conn = createConnection();
            if (conn) {
                currentConnections++;
            }
        }
        return conn;
    }
    // å½’还数据库连接
    void releaseConnection(std::unique_ptr<sql::Connection>& conn) {
        std::lock_guard<std::mutex> lock(mutex);
        if (currentConnections > minConnections) {
            currentConnections--;
        } else {
            connections.push_back(std::move(conn));
        }
        cv.notify_one();
    }
};
std::mutex SQLConnectionPool::mutex;
SQLConnectionPool* SQLConnectionPool::instance = nullptr;
Server/ÍõçûÔª/document/·À×¢Èë.txt
New file
@@ -0,0 +1,67 @@
#include <iostream>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <string>
#include <regex>
class DatabaseUtils {
public:
    // è¿žæŽ¥æ•°æ®åº“
    static sql::Connection* connect() {
        try {
            sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
            sql::Connection* con = driver->connect("tcp://127.0.0.1:3306", "mayi", "123456");
            con->setSchema("your_database");
            return con;
        } catch (sql::SQLException& e) {
            std::cerr << "数据库连接错误: " << e.what() << std::endl;
            return nullptr;
        }
    }
    // æ£€æŸ¥SQL语句是否存在潜在注入风险(简单正则校验)
    static bool isSafeSQL(const std::string& sql) {
        // ç®€å•的正则表达式,防止常见的注入关键词
        std::regex injectionRegex("(drop|delete|update|insert|select\\s+\\*\\s+from)", std::regex_constants::icase);
        return!std::regex_search(sql, injectionRegex);
    }
    // ä½¿ç”¨å‚数化查询执行SQL语句
    static sql::ResultSet* executeSafeQuery(sql::Connection* con, const std::string& sql, const std::vector<std::string>& params) {
        try {
            sql::PreparedStatement* pstmt = con->prepareStatement(sql);
            for (size_t i = 0; i < params.size(); ++i) {
                pstmt->setString(i + 1, params[i]);
            }
            return pstmt->executeQuery();
        } catch (sql::SQLException& e) {
            std::cerr << "查询执行错误: " << e.what() << std::endl;
            return nullptr;
        }
    }
};
int main() {
    sql::Connection* con = DatabaseUtils::connect();
    if (con) {
        std::string sql = "SELECT * FROM your_table WHERE column_name =?";
        std::vector<std::string> params = {"test_value"};
        if (DatabaseUtils::isSafeSQL(sql)) {
            sql::ResultSet* res = DatabaseUtils::executeSafeQuery(con, sql, params);
            if (res) {
                while (res->next()) {
                    // å¤„理结果
                    std::cout << res->getString(1) << std::endl;
                }
                delete res;
            }
        } else {
            std::cerr << "潜在的SQL注入风险" << std::endl;
        }
        delete con;
    }
    return 0;
}
Server/ÂíÀöƼ/code/log/.vscode/c_cpp_properties.json
New file
@@ -0,0 +1,18 @@
{
  "configurations": [
    {
      "name": "windows-gcc-x64",
      "includePath": [
        "${workspaceFolder}/**"
      ],
      "compilerPath": "gcc",
      "cStandard": "${default}",
      "cppStandard": "${default}",
      "intelliSenseMode": "windows-gcc-x64",
      "compilerArgs": [
        ""
      ]
    }
  ],
  "version": 4
}
Server/ÂíÀöƼ/code/log/.vscode/launch.json
New file
@@ -0,0 +1,24 @@
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "C/C++ Runner: Debug Session",
      "type": "cppdbg",
      "request": "launch",
      "args": [],
      "stopAtEntry": false,
      "externalConsole": true,
      "cwd": "d:/git_1026/昆仑_1025/Server/马丽萍/code/log",
      "program": "d:/git_1026/昆仑_1025/Server/马丽萍/code/log/build/Debug/outDebug",
      "MIMode": "gdb",
      "miDebuggerPath": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ]
    }
  ]
}
Server/ÂíÀöƼ/code/log/.vscode/settings.json
New file
@@ -0,0 +1,59 @@
{
  "C_Cpp_Runner.cCompilerPath": "gcc",
  "C_Cpp_Runner.cppCompilerPath": "g++",
  "C_Cpp_Runner.debuggerPath": "gdb",
  "C_Cpp_Runner.cStandard": "",
  "C_Cpp_Runner.cppStandard": "",
  "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
  "C_Cpp_Runner.useMsvc": false,
  "C_Cpp_Runner.warnings": [
    "-Wall",
    "-Wextra",
    "-Wpedantic",
    "-Wshadow",
    "-Wformat=2",
    "-Wcast-align",
    "-Wconversion",
    "-Wsign-conversion",
    "-Wnull-dereference"
  ],
  "C_Cpp_Runner.msvcWarnings": [
    "/W4",
    "/permissive-",
    "/w14242",
    "/w14287",
    "/w14296",
    "/w14311",
    "/w14826",
    "/w44062",
    "/w44242",
    "/w14905",
    "/w14906",
    "/w14263",
    "/w44265",
    "/w14928"
  ],
  "C_Cpp_Runner.enableWarnings": true,
  "C_Cpp_Runner.warningsAsError": false,
  "C_Cpp_Runner.compilerArgs": [],
  "C_Cpp_Runner.linkerArgs": [],
  "C_Cpp_Runner.includePaths": [],
  "C_Cpp_Runner.includeSearch": [
    "*",
    "**/*"
  ],
  "C_Cpp_Runner.excludeSearch": [
    "**/build",
    "**/build/**",
    "**/.*",
    "**/.*/**",
    "**/.vscode",
    "**/.vscode/**"
  ],
  "C_Cpp_Runner.useAddressSanitizer": false,
  "C_Cpp_Runner.useUndefinedSanitizer": false,
  "C_Cpp_Runner.useLeakSanitizer": false,
  "C_Cpp_Runner.showCompilationTime": false,
  "C_Cpp_Runner.useLinkTimeOptimization": false,
  "C_Cpp_Runner.msvcSecureNoWarnings": false
}
Server/ÂíÀöƼ/code/log/README.md
New file
@@ -0,0 +1,9 @@
同步/异步日志系统
===============
同步/异步日志系统主要涉及了两个模块,一个是日志模块,一个是阻塞队列模块,其中加入阻塞队列模块主要是解决异步写入日志做准备.
> * è‡ªå®šä¹‰é˜»å¡žé˜Ÿåˆ—
> * å•例模式创建日志
> * åŒæ­¥æ—¥å¿—
> * å¼‚步日志
> * å®žçŽ°æŒ‰å¤©ã€è¶…è¡Œåˆ†ç±»
Server/ÂíÀöƼ/code/log/block_queue.h
New file
@@ -0,0 +1,212 @@
/*************************************************************
*循环数组实现的阻塞队列,m_back = (m_back + 1) % m_max_size;
*线程安全,每个操作前都要先加互斥锁,操作完后,再解锁
**************************************************************/
#ifndef BLOCK_QUEUE_H
#define BLOCK_QUEUE_H
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
#include "../lock/locker.h"
using namespace std;
template <class T>
class block_queue
{
public:
    block_queue(int max_size = 1000)
    {
        if (max_size <= 0)
        {
            exit(-1);
        }
        m_max_size = max_size;
        m_array = new T[max_size];
        m_size = 0;
        m_front = -1;
        m_back = -1;
    }
    void clear()
    {
        m_mutex.lock();
        m_size = 0;
        m_front = -1;
        m_back = -1;
        m_mutex.unlock();
    }
    ~block_queue()
    {
        m_mutex.lock();
        if (m_array != NULL)
            delete [] m_array;
        m_mutex.unlock();
    }
    //判断队列是否满了
    bool full()
    {
        m_mutex.lock();
        if (m_size >= m_max_size)
        {
            m_mutex.unlock();
            return true;
        }
        m_mutex.unlock();
        return false;
    }
    //判断队列是否为空
    bool empty()
    {
        m_mutex.lock();
        if (0 == m_size)
        {
            m_mutex.unlock();
            return true;
        }
        m_mutex.unlock();
        return false;
    }
    //返回队首元素
    bool front(T &value)
    {
        m_mutex.lock();
        if (0 == m_size)
        {
            m_mutex.unlock();
            return false;
        }
        value = m_array[m_front];
        m_mutex.unlock();
        return true;
    }
    //返回队尾元素
    bool back(T &value)
    {
        m_mutex.lock();
        if (0 == m_size)
        {
            m_mutex.unlock();
            return false;
        }
        value = m_array[m_back];
        m_mutex.unlock();
        return true;
    }
    int size()
    {
        int tmp = 0;
        m_mutex.lock();
        tmp = m_size;
        m_mutex.unlock();
        return tmp;
    }
    int max_size()
    {
        int tmp = 0;
        m_mutex.lock();
        tmp = m_max_size;
        m_mutex.unlock();
        return tmp;
    }
    //往队列添加元素,需要将所有使用队列的线程先唤醒
    //当有元素push进队列,相当于生产者生产了一个元素
    //若当前没有线程等待条件变量,则唤醒无意义
    bool push(const T &item)
    {
        m_mutex.lock();
        if (m_size >= m_max_size)
        {
            m_cond.broadcast();
            m_mutex.unlock();
            return false;
        }
        m_back = (m_back + 1) % m_max_size;
        m_array[m_back] = item;
        m_size++;
        m_cond.broadcast();
        m_mutex.unlock();
        return true;
    }
    //pop时,如果当前队列没有元素,将会等待条件变量
    bool pop(T &item)
    {
        m_mutex.lock();
        while (m_size <= 0)
        {
            if (!m_cond.wait(m_mutex.get()))
            {
                m_mutex.unlock();
                return false;
            }
        }
        m_front = (m_front + 1) % m_max_size;
        item = m_array[m_front];
        m_size--;
        m_mutex.unlock();
        return true;
    }
    //增加了超时处理
    bool pop(T &item, int ms_timeout)
    {
        struct timespec t = {0, 0};
        struct timeval now = {0, 0};
        gettimeofday(&now, NULL);
        m_mutex.lock();
        if (m_size <= 0)
        {
            t.tv_sec = now.tv_sec + ms_timeout / 1000;
            t.tv_nsec = (ms_timeout % 1000) * 1000;
            if (!m_cond.timewait(m_mutex.get(), t))
            {
                m_mutex.unlock();
                return false;
            }
        }
        if (m_size <= 0)
        {
            m_mutex.unlock();
            return false;
        }
        m_front = (m_front + 1) % m_max_size;
        item = m_array[m_front];
        m_size--;
        m_mutex.unlock();
        return true;
    }
private:
    locker m_mutex;
    cond m_cond;
    T *m_array;
    int m_size;
    int m_max_size;
    int m_front;
    int m_back;
};
#endif
Server/ÂíÀöƼ/code/log/log.cpp
New file
@@ -0,0 +1,164 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include "log.h"
#include <pthread.h>
using namespace std;
Log::Log()
{
    m_count = 0;
    m_is_async = false;
}
Log::~Log()
{
    if (m_fp != NULL)
    {
        fclose(m_fp);
    }
}
//异步需要设置阻塞队列的长度,同步不需要设置
bool Log::init(const char *file_name, int close_log, int log_buf_size, int split_lines, int max_queue_size)
{
    //如果设置了max_queue_size,则设置为异步
    if (max_queue_size >= 1)
    {
        m_is_async = true;
        m_log_queue = new block_queue<string>(max_queue_size);
        pthread_t tid;
        //flush_log_thread为回调函数,这里表示创建线程异步写日志
        pthread_create(&tid, NULL, flush_log_thread, NULL);
    }
    m_close_log = close_log;
    m_log_buf_size = log_buf_size;
    m_buf = new char[m_log_buf_size];
    memset(m_buf, '\0', m_log_buf_size);
    m_split_lines = split_lines;
    time_t t = time(NULL);
    struct tm *sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;
    const char *p = strrchr(file_name, '/');
    char log_full_name[256] = {0};
    if (p == NULL)
    {
        snprintf(log_full_name, 255, "%d_%02d_%02d_%s", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, file_name);
    }
    else
    {
        strcpy(log_name, p + 1);
        strncpy(dir_name, file_name, p - file_name + 1);
        snprintf(log_full_name, 255, "%s%d_%02d_%02d_%s", dir_name, my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, log_name);
    }
    m_today = my_tm.tm_mday;
    m_fp = fopen(log_full_name, "a");
    if (m_fp == NULL)
    {
        return false;
    }
    return true;
}
void Log::write_log(int level, const char *format, ...)
{
    struct timeval now = {0, 0};
    gettimeofday(&now, NULL);
    time_t t = now.tv_sec;
    struct tm *sys_tm = localtime(&t);
    struct tm my_tm = *sys_tm;
    char s[16] = {0};
    switch (level)
    {
    case 0:
        strcpy(s, "[debug]:");
        break;
    case 1:
        strcpy(s, "[info]:");
        break;
    case 2:
        strcpy(s, "[warn]:");
        break;
    case 3:
        strcpy(s, "[erro]:");
        break;
    default:
        strcpy(s, "[info]:");
        break;
    }
    //写入一个log,对m_count++, m_split_lines最大行数
    m_mutex.lock();
    m_count++;
    if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //everyday log
    {
        char new_log[256] = {0};
        fflush(m_fp);
        fclose(m_fp);
        char tail[16] = {0};
        snprintf(tail, 16, "%d_%02d_%02d_", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday);
        if (m_today != my_tm.tm_mday)
        {
            snprintf(new_log, 255, "%s%s%s", dir_name, tail, log_name);
            m_today = my_tm.tm_mday;
            m_count = 0;
        }
        else
        {
            snprintf(new_log, 255, "%s%s%s.%lld", dir_name, tail, log_name, m_count / m_split_lines);
        }
        m_fp = fopen(new_log, "a");
    }
    m_mutex.unlock();
    va_list valst;
    va_start(valst, format);
    string log_str;
    m_mutex.lock();
    //写入的具体时间内容格式
    int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d.%06ld %s ",
                     my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday,
                     my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, s);
    int m = vsnprintf(m_buf + n, m_log_buf_size - n - 1, format, valst);
    m_buf[n + m] = '\n';
    m_buf[n + m + 1] = '\0';
    log_str = m_buf;
    m_mutex.unlock();
    if (m_is_async && !m_log_queue->full())
    {
        m_log_queue->push(log_str);
    }
    else
    {
        m_mutex.lock();
        fputs(log_str.c_str(), m_fp);
        m_mutex.unlock();
    }
    va_end(valst);
}
void Log::flush(void)
{
    m_mutex.lock();
    //强制刷新写入流缓冲区
    fflush(m_fp);
    m_mutex.unlock();
}
Server/ÂíÀöƼ/code/log/log.h
New file
@@ -0,0 +1,69 @@
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <pthread.h>
#include "block_queue.h"
using namespace std;
class Log
{
public:
    //C++11以后,使用局部变量懒汉不用加锁
    static Log *get_instance()
    {
        static Log instance;
        return &instance;
    }
    static void *flush_log_thread(void *args)
    {
        Log::get_instance()->async_write_log();
    }
    //可选择的参数有日志文件、日志缓冲区大小、最大行数以及最长日志条队列
    bool init(const char *file_name, int close_log, int log_buf_size = 8192, int split_lines = 5000000, int max_queue_size = 0);
    void write_log(int level, const char *format, ...);
    void flush(void);
private:
    Log();
    virtual ~Log();
    void *async_write_log()
    {
        string single_log;
        //从阻塞队列中取出一个日志string,写入文件
        while (m_log_queue->pop(single_log))
        {
            m_mutex.lock();
            fputs(single_log.c_str(), m_fp);
            m_mutex.unlock();
        }
    }
private:
    char dir_name[128]; //路径名
    char log_name[128]; //log文件名
    int m_split_lines;  //日志最大行数
    int m_log_buf_size; //日志缓冲区大小
    long long m_count;  //日志行数记录
    int m_today;        //因为按天分类,记录当前时间是那一天
    FILE *m_fp;         //打开log的文件指针
    char *m_buf;
    block_queue<string> *m_log_queue; //阻塞队列
    bool m_is_async;                  //是否同步标志位
    locker m_mutex;
    int m_close_log; //关闭日志
};
#define LOG_DEBUG(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(0, format, ##__VA_ARGS__); Log::get_instance()->flush();}
#define LOG_INFO(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(1, format, ##__VA_ARGS__); Log::get_instance()->flush();}
#define LOG_WARN(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(2, format, ##__VA_ARGS__); Log::get_instance()->flush();}
#define LOG_ERROR(format, ...) if(0 == m_close_log) {Log::get_instance()->write_log(3, format, ##__VA_ARGS__); Log::get_instance()->flush();}
#endif
Server/ÂíÀöƼ/document/ÈÕÖ¾ÐèÇó·ÖÎöÎĵµ.docx
Binary files differ
Server/ÂíÓ庼/document/°æ±¾¸üй¦ÄÜÐèÇó_server.docx
Binary files differ
²Î¿¼Îĵµ/ÐèÇó·ÖÎöÄ£°å/~$Çó¹¦Äܹæ¸ñ˵Ã÷Êé_2.docx
Binary files differ
ÈÕÖ¾ÐèÇó·ÖÎöÎĵµ.docx
Binary files differ