240717班级,工业化控制系统,煤矿相关行业,昆仑系统
gong
2024-10-29 a905d895b043eea4ebdf05e9775e0567378cc148
Merge branch 'master' of ssh://115.28.86.8:29418/~admin/昆仑_1025
10个文件已修改
11个文件已添加
2个文件已删除
858 ■■■■■ 已修改文件
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/历史查询分析模块需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Client/黎弘霖/document/设备管理需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/单例模式封装.txt 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/备份导出.txt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库模块需求分析.docx 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/数据库连接池类.txt 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/document/防注入.txt 94 ●●●● 补丁 | 查看 | 原始文档 | 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/版本更新功能需求_server.docx 补丁 | 查看 | 原始文档 | blame | 历史
参考文档/需求分析模板/~$求功能规格说明书_2.docx 补丁 | 查看 | 原始文档 | blame | 历史
昆仑项目文件/昆仑项目风险管理表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
Client/¼½ºÆêÆ/document/Éú²ú¼Æ»®¹ÜÀí_ÐèÇó·ÖÎö.docx
Binary files differ
Client/Áõ×Óº½/document/À¥ÂØ_¾¯±¨¹ÜÀí.docx
Binary files differ
Client/½ª¿É¸ý/document/ȨÏÞ¹ÜÀíÐèÇó·ÖÎö.docx
Binary files differ
Client/ËÎ껕i/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
Server/ÍõçûÔª/document/µ¥Àýģʽ·â×°.txt
@@ -1,62 +1,51 @@
#include <iostream>
#include <memory>
#include <mutex>
#include <fstream>
#include <string>
#include <ctime>
using namespace std;
class A {
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
class DatabaseOperator {
private:
    ofstream logFile;
    A() {
        logFile.open("123.txt", ios::app);
    // ç§æœ‰æž„造函数
    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;
        }
    }
    ~A() {
        logFile.close();
    }
    A(const A &t){}
    A& operator=(const A &t){}
    static A* volatile s_obj;
    static mutex g_mutex;
    static DatabaseOperator* instance;
    static std::mutex mutex;
    sql::Driver* driver;
    std::unique_ptr<sql::Connection> connection;
public:
    static A* getInstance() {
        if (s_obj == nullptr) {
            lock_guard<mutex> guard(g_mutex);
            if (s_obj == nullptr) {
                s_obj = new A;
            }
    // èŽ·å–å•ä¾‹å®žä¾‹
    static DatabaseOperator* getInstance() {
        std::lock_guard<std::mutex> lock(mutex);
        if (instance == nullptr) {
            instance = new DatabaseOperator();
        }
        return s_obj;
        return instance;
    }
    void write(const string& level, const string& description, const string& time) {
        logFile << "[" << level << "] " << "[" << time << "] " << description << endl;
    }
    void release() {
        if (s_obj) {
            delete s_obj;
            s_obj = nullptr;
    // æ‰§è¡ŒæŸ¥è¯¢æ“ä½œï¼ˆç¤ºä¾‹ï¼‰
    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;
    }
};
A* volatile A::s_obj = nullptr;
mutex A::g_mutex;
int main() {
    A* a1 = A::getInstance();
    A* a2 = A::getInstance();
    if (a1 == a2) {
        cout << "单例成功" << endl;
    }
    else {
        cout << "单例失败" << endl;
    }
    time_t now = time(nullptr);
    char buffer[80];
    struct tm timeinfo;
    localtime_s(&timeinfo, &now);
    strftime(buffer, 80, "%Y - %m - %d %H:%M:%S", &timeinfo);
    string timeStr(buffer);
    a1->write("1", "日志", timeStr);
    a1->release();
    return 0;
}
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/Êý¾Ý¿âÁ¬½Ó³ØÀà.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
@@ -1,29 +1,67 @@
https://blog.csdn.net/qq_28245087/article/details/131453274
1 .使用参数化查询
使用参数化查询可以防止SQL注入攻击,并提高代码的可读性和可维护性。在Java中,可以使用PreparedStatement来实现参数化查询。
2. è¾“入验证和过滤
输入验证和过滤是一种用于确保用户输入数据的安全性和有效性的技术。它可以防止恶意输入和错误数据导致的安全漏洞和应用程序错误。
3. ä½¿ç”¨å­˜å‚¨è¿‡ç¨‹
存储过程是一组预定义的SQL语句集合,可以在数据库中进行重复性和复杂性的操作。它们可以接受参数,并且可以在数据库中进行重复使用。
4.最小权限原则
最小权限原则是一种安全性原则,指的是为了保护敏感数据和系统资源,用户应该被授予最小必需的权限。这意味着用户只能访问和执行他们工作所需的数据库对象和操作,而不是拥有对整个数据库的完全访问权限。
使用最小权限原则可以减少潜在的安全风险和数据泄露的可能性。通过限制用户的权限,可以防止他们对数据库中的敏感数据进行未经授权的访问、修改或删除。
5. ä½¿ç”¨ORM框架
ORM(对象关系映射)框架是一种将对象模型和关系数据库之间进行映射的技术。它允许开发人员使用面向对象的方式操作数据库,而不需要编写繁琐的SQL语句。ORM框架将数据库表映射为对象,将表的行映射为对象的属性,将表之间的关系映射为对象之间的关联。
ORM框架的优点包括提高开发效率、减少代码量、简化数据库操作、提供对象级别的查询和持久化等。
6. ä½¿ç”¨å‡†å¤‡è¯­å¥
准备语句(Prepared Statement)是一种预编译的SQL语句,它允许开发人员将参数化查询发送到数据库,并在执行时提供参数值。准备语句可以提高数据库操作的性能和安全性,同时还能防止SQL注入攻击。
7.使用安全的数据库连接
使用安全的数据库连接是非常重要的,可以保护数据库免受恶意攻击和数据泄露。
使用SSL/TLS加密:通过使用SSL/TLS加密,可以确保数据库连接在传输过程中的数据安全。
8.避免动态拼接SQL语句
避免动态拼接SQL语句是为了防止SQL注入攻击和提高代码的可读性和可维护性。
9.使用防火墙和入侵检测系统
使用防火墙和入侵检测系统是为了保护计算机网络免受未经授权的访问和恶意攻击。
10.定期更新和维护数据库软件
定期更新和维护数据库软件是非常重要的,以确保数据库的安全性、性能和功能的稳定性。以下是一些说明和解释,以及使用Java代码示例来实现数据库软件的定期更新和维护:
#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/°æ±¾¸üй¦ÄÜÐèÇó_server.docx
Binary files differ
²Î¿¼Îĵµ/ÐèÇó·ÖÎöÄ£°å/~$Çó¹¦Äܹæ¸ñ˵Ã÷Êé_2.docx
Binary files differ
À¥ÂØÏîÄ¿Îļþ/À¥ÂØÏîÄ¿·çÏÕ¹ÜÀí±í.xlsx
Binary files differ