MALOUDA-PSA 2025-04-05 16:13 采纳率: 85.6%
浏览 4
已结题

c++之内存泄露问题朔源


thread_local MYSQL* thread_mysql_conn = nullptr;

struct stkvec {
    char stkcode[7];  
    char stkname[21]; 
};


std::string wstringToString(const std::wstring& wstr) {
    if (wstr.empty()) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}


std::vector<stkvec> stkvecs;

std::wstring utf82wstring(const std::string& str)
{
    if (str.empty()) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

bool FetchDataVec() {
    HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, L"Global\\MySharedMemory");
    if (hMapFile == NULL) {
        std::cerr << "Error opening shared memory: " << GetLastError() << std::endl;
        return false;
    }

    LPVOID pBuf = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
    if (pBuf == NULL) {
        std::cerr << "Error mapping view of file: " << GetLastError() << std::endl;
        CloseHandle(hMapFile);
        return false;
    }

    char* dataPtr = static_cast<char*>(pBuf);

    int recordCount = *reinterpret_cast<int*>(dataPtr);
    dataPtr += sizeof(int); 

    const int RECORD_SIZE = 6 + 20; 

    if (recordCount <= 0) {
        std::cerr << "Invalid record count: " << recordCount << std::endl;
        UnmapViewOfFile(pBuf);
        CloseHandle(hMapFile);
        return false;
    }

    stkvecs.clear();

    for (int i = 0; i < recordCount; ++i) {
        stkvec vec;

        // 读取 stkcode(6 字节)
        memcpy(vec.stkcode, dataPtr, 6);
        vec.stkcode[6] = '\0'; 
        dataPtr += 6;

        // 读取 stkname(20 字节)
        memcpy(vec.stkname, dataPtr, 20);
        vec.stkname[20] = '\0'; 
        dataPtr += 20;

        // 将 vec 添加到 stkvecs 中
        stkvecs.push_back(vec);
    }

    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);

    return true;
}


std::string cstrToStdString(const char* cstr, size_t max_len) {
    return std::string(cstr, strnlen(cstr, max_len));
}

std::string cleanName(const std::string& name) {
    std::string cleaned = std::regex_replace(name, std::regex("\\s+"), " "); 
    cleaned = std::regex_replace(cleaned, std::regex("^\\s+|\\s+$"), "");  
    return cleaned;
}

void cleanup_thread_mysql_connection() {
    if (thread_mysql_conn) {
        mysql_close(thread_mysql_conn);
        thread_mysql_conn = nullptr;
    }
}


std::string escapeRegex(const std::string& str) {
    return std::regex_replace(str, std::regex(R"([\^$.|?*+(){}$$])"), R"(\$&)");
}

std::string preprocessText(const std::string& text) {
    std::string cleaned = std::regex_replace(text, std::regex("<[^>]*>"), ""); 
    cleaned = std::regex_replace(cleaned, std::regex("&nbsp;"), " ");           
    cleaned = std::regex_replace(cleaned, std::regex("\\s+"), " ");            
    cleaned = std::regex_replace(cleaned, std::regex("^\\s+|\\s+$"), "");  
    return cleaned;
}

std::vector<std::string> findMatchesWithRegex(const std::vector<stkvec>& stkvecs, const std::string& text) {
    std::vector<std::string> matches;
    std::string pattern;



    for (const auto& vec : stkvecs) {
        std::string stkname_str = cstrToStdString(vec.stkname, sizeof(vec.stkname)); // 转换为 std::string
        if (!stkname_str.empty()) { 
            std::string cleaned_name = cleanName(stkname_str); 
            if (!cleaned_name.empty()) {  
                if (!pattern.empty()) pattern += "|";  
                pattern += escapeRegex(cleaned_name);  
            }
        }
    }


    try {
       
        std::string processed_text = preprocessText(text);
    
        std::regex re(pattern, std::regex_constants::icase); 
        auto words_begin = std::sregex_iterator(processed_text.begin(), processed_text.end(), re);
        auto words_end = std::sregex_iterator();

     
        for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
            std::smatch match = *i;
            std::string matched_str = match.str();

            auto it = std::find_if(stkvecs.begin(), stkvecs.end(), [&matched_str](const stkvec& vec) {
                std::string stkname_str = cstrToStdString(vec.stkname, sizeof(vec.stkname));
                return cleanName(stkname_str) == matched_str;
                });

            if (it != stkvecs.end()) {
                std::string stkcode_str = cstrToStdString(it->stkcode, sizeof(it->stkcode));
                matches.push_back(stkcode_str);
                //std::cout << "Found match for: " << matched_str << " -> stkcode: " << stkcode_str << std::endl;
            }
            else {
                std::cout << "No match found for: " << matched_str << std::endl;
            }
        }

        std::cout << "Found " << matches.size() << " matches." << std::endl;
    }
    catch (const std::regex_error& e) {
        std::cerr << "Regex error: " << e.what() << std::endl;
    }

    return matches;
}
std::string extractJsonField(const std::string& jsonStr, const std::string& field);


//MYSQL* global_mysql_conn = nullptr;

using namespace std;



bool init_thread_mysql_connection(const std::string& host, const std::string& user, const std::string& passwd, const std::string& db, int port) {
    printf("Initializing MySQL connection to %s:%d...\n", host.c_str(), port);
    MYSQL* conn = mysql_init(nullptr);
    if (!conn) {
        fprintf(stderr, "Failed to initialize MySQL connection.\n");
        return false;
    }

    if (!mysql_real_connect(conn, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0)) {
        fprintf(stderr, "Failed to connect to MySQL: %s\n", mysql_error(conn));
        mysql_close(conn);
        return false;
    }

    printf("MySQL connection initialized successfully.\n");
    thread_mysql_conn = conn;  
    return true;
}



bool IsValidFloat(float fval) {
    if (std::isnan(fval)) {
        
        return false;
    }
    if (std::isinf(fval)) {
        // fval is either positive or negative infinity
        return false;
    }
  
    return true;
}

LPTDXDAT2 FetchDataNameFromMySQL(MYSQL* conn, const std::string& stkcode) {
   

    MYSQL_RES* res = nullptr;
    MYSQL_ROW row;
    LPTDXDAT2 data = nullptr;

    if (conn == nullptr) {
        fprintf(stderr, "0000Connection is null. Reinitializing...\n");
        if (!init_thread_mysql_connection("localhost", "admin", "Zls_[20]", "stock", 3306)){
            fprintf(stderr, "-------1111Connection is null. Reinitializing...\n");
            return nullptr;
        }
    }

   
    mysql_query(conn, "SET NAMES 'utf8mb4'");

    std::setlocale(LC_ALL, "zh_CN.UTF-8");
    mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");       //必须使用utf8, 原因不知道
    if (mysql_set_character_set(conn, "utf8") != 0) {
        std::cerr << "Error setting character set to utf8: " << mysql_error(conn) << std::endl;
    }



    char query[256];
    snprintf(query, sizeof(query), "SELECT stknew,roe,mgsy,score,height,c2exp12,c2exp50,stkname,stkcode,c2exp12wk,c2exp50wk,seasonratio FROM fxj WHERE stkcode='%s'", stkcode.c_str());
   

    if (mysql_query(conn, query)) {
        fprintf(stderr, "2 SELECT query error: %s\n", mysql_error(conn));
        mysql_close(conn);
        return nullptr;
    }

    res = mysql_store_result(conn);

    if (res) {
        if ((row = mysql_fetch_row(res)) != NULL) {
            // 分配内存给data
            data = (LPTDXDAT2)calloc(1, sizeof(TDXDAT2));
            if (!data) {
                fprintf(stderr, "Memory allocation failed\n");
                mysql_free_result(res);
                mysql_close(conn);
                return nullptr;
            }

       

            data->stknew = atof(row[0]);
            data->roe = atof(row[1]);
            data->mgsy = atof(row[2]);
            data->score = atoi(row[3]);
            data->height = atoi(row[4]);
            data->c2exp12 = atoi(row[5]);
            data->c2exp50 = atoi(row[6]);
            data->c2exp12wk = atoi(row[9]);
            data->c2exp50wk = atoi(row[10]);
            data->seasonratio = atof(row[11]);
       
            data->stkname = row[7] ? std::string(row[7]) : ""; // 使用std::string构造函数进行转换
         
            data->stkcode = row[8] ? std::string(row[8]) : "";
      
        }
        else {
            printf("No rows returned for stkname: %s\n", stkcode.c_str());
        }
        mysql_free_result(res);
    }

  
    return data;
}


LPTDXDAT2 FetchDataFromMySQL(MYSQL* conn, const std::string& stkcode) {

    MYSQL_RES* res = nullptr;
    MYSQL_ROW row;
    LPTDXDAT2 data = nullptr;

    if (conn == NULL) {
        fprintf(stderr, "Connection is 22null\n");
        return nullptr;
    }


    std::setlocale(LC_ALL, "zh_CN.UTF-8");
    mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8");       //必须使用utf8, 原因不知道
    if (mysql_set_character_set(conn, "utf8") != 0) {
        std::cerr << "Error setting character set to utf8: " << mysql_error(conn) << std::endl;
    }



    char query[256];
    snprintf(query, sizeof(query), "SELECT stknew,roe,mgsy,score,height,c2exp12,c2exp50 FROM fxj WHERE stkcode='%s'", stkcode.c_str());

    if (mysql_query(conn, query)) {
        fprintf(stderr, "1  SELECT query error: %s\n", mysql_error(conn));
        mysql_close(conn);
        return nullptr;
    }

    res = mysql_store_result(conn);

    if (res) {
        if ((row = mysql_fetch_row(res)) != NULL) {
            // 分配内存给data
            data = (LPTDXDAT2)calloc(1, sizeof(TDXDAT2));
            if (!data) {
                fprintf(stderr, "Memory allocation failed\n");
                mysql_free_result(res);
                mysql_close(conn);
                return nullptr;
            }

            // 设置stkcode
            data->stkcode = stkcode;
            data->stkname = ""; // 假设没有从数据库获取stkname

            data->stknew = atof(row[0]);
            data->roe = atof(row[1]);
            data->mgsy = atof(row[2]);
            data->score = atoi(row[3]);
            data->height = atoi(row[4]);
            data->c2exp12 = atoi(row[5]);
            data->c2exp50 = atoi(row[6]);
        }
        else {
            printf("No rows returned for stkcode: %s\n", stkcode.c_str());
        }
        mysql_free_result(res);
    }

    mysql_close(conn);
    return data;
}


void init_openssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

void cleanup_openssl() {
    EVP_cleanup();
}

SSL_CTX* create_context() {
    const SSL_METHOD* method;
    SSL_CTX* ctx;

    method = TLS_server_method();
    ctx = SSL_CTX_new(method);
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    return ctx;
}

void parseHtmlTableToStruct(const char* fileName, std::vector<TDXDAT2>& dataOut)
{
    pugi::xml_document doc;
    if (!doc.load_file(fileName)) {
        std::cerr << "Failed to load file: " << fileName << std::endl;
        return;
    }

    pugi::xml_node table = doc.child("html").child("body").child("table");
    for (pugi::xml_node row : table.children("tr"))
    {
        // 跳过表头
        if (std::string(row.child_value("th")) == "stkcode") continue;

        TDXDAT2 data;
        int colIndex = 0;
        for (pugi::xml_node cell : row.children("td"))
        {
            const char* text = cell.child_value();
            switch (colIndex++)
            {
            case 0: data.stkcode = text; break;
            case 1: data.stkname = text; break;
            case 2: data.stknew = std::stof(text); break;
            case 3: data.roe = std::stof(text); break;
            case 4: data.mgsy = std::stof(text); break; // 注意: 这里可能需要调整类型
            case 5: data.score = std::stoi(text); break;
            case 6: data.height = std::stoi(text); break;
            case 7: data.c2exp12 = std::stoi(text); break; // 注意: 这里可能需要调整类型
            case 8: data.c2exp50 = std::stoi(text); break; // 注意: 这里可能需要调整类型
            }
        }
        dataOut.push_back(data);
    }
}



void configure_context(SSL_CTX* ctx) {

    std::ifstream certFile("C:\\sys\\cert.pem", std::ios::binary);
    if (!certFile.is_open()) {
        std::cerr << "Failed to open certificate file." << std::endl;
        return;
    }

    std::cout << "Successfully opened certificate file." << std::endl;

    SSL_CTX_set_ecdh_auto(ctx, 1);



    if (SSL_CTX_use_certificate_file(ctx, "C:\\sys\\cert.pem", SSL_FILETYPE_PEM) <= 0) {
        // 创建一个内存 BIO 来捕获错误信息
        BIO* bio = BIO_new(BIO_s_mem());
        if (bio != nullptr) {
            ERR_print_errors(bio); // 将错误信息打印到 BIO

            // 从 BIO 中读取数据并写入字符串流
            char buffer[1024];
            std::ostringstream oss;
            int len;
            while ((len = BIO_read(bio, buffer, sizeof(buffer))) > 0) {
                oss.write(buffer, len);
            }
            BIO_free(bio);

 
            std::ofstream logFile("c:\\sys\\error.log", std::ios::app);
            if (logFile.is_open()) {
                if (logFile.fail()) {
                    std::cerr << "Log file open failed with failbit set." << std::endl;
                }
                if (logFile.bad()) {
                    std::cerr << "Log file open failed with badbit set." << std::endl;
                }
                logFile << oss.str(); // 将错误信息写入日志文件
                logFile << "Failed to load certificate file.\n";
                logFile.close();
            }
            else {
                std::cerr << "Failed to open error log file." << std::endl;
            }
        }
        else {
            std::cerr << "Failed to create BIO for error logging." << std::endl;
        }

    
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, "C:\\sys\\key.pem", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
}

void saveToJson1(const char* fileName, std::vector<std::vector<std::string>>& data)
{

    std::ofstream outFile(fileName);
    if (!outFile.is_open())
    {

        std::cout << "文件:'" << fileName << "' 打开失败,请确认文件是否被占用。" << std::endl;
        return;
    }

    std::vector<std::string> title = data[0];

    outFile << "[" << std::endl;

    for (size_t row = 1; row < data.size(); row++)
    {

        outFile << "{" << std::endl;
        for (size_t col = 0; col < data[row].size(); col++)
        {
            outFile << title[col] << ":" << data[row][col];

            if (col < data[row].size() - 1)
            {

                outFile << ",";
            }
            outFile << std::endl;
        }
        if (row < data.size() - 1)
        {
            outFile << "}," << std::endl;
        }
        else
        {

            outFile << "}" << std::endl;
        }
    }

    outFile << "]" << std::endl;
    outFile.close();
}



std::string saveToJson(std::vector<std::vector<std::string>>& data)
{
    std::ostringstream jsonString;

    /// data的第0行是标题,所以从第一行开始
    if (data.empty()) {
        return "{}"; // 或者其它处理空数据的方式
    }
    std::vector<std::string> title = data[0];

    jsonString << "[" << std::endl;

    for (size_t row = 1; row < data.size(); row++)
    {
        jsonString << "{" << std::endl;
        for (size_t col = 0; col < data[row].size(); col++)
        {
            jsonString << "\"" << title[col] << "\": \"" << data[row][col] << "\"";

            if (col < data[row].size() - 1)
            {
                jsonString << ",";
            }
            jsonString << std::endl;
        }
        if (row < data.size() - 1)
        {
            jsonString << "}," << std::endl;
        }
        else
        {
            jsonString << "}" << std::endl;
        }
    }

    jsonString << "]" << std::endl;

    return jsonString.str();
}

std::string generateHtmlFromLstData(const std::vector<TDXDAT2>& lstData) {
    std::stringstream ss;

   
    ss << "<html><head><meta charset='UTF-8'></head><body><table>";

  
    ss << "<thead><tr>"
        << "<th width='10%'>Code</th>"
        << "<th width='10%'>Name</th>"
        << "<th width='10%'>New</th>"
        << "<th width='10%'>ROE</th>"
        << "<th width='10%'>MGSY</th>"
        << "<th width='10%'>Score</th>"
        << "<th width='10%'>Height</th>"
        << "<th width='10%'>ExpMA12</th>"
        << "<th width='10%'>ExpMA50</th>"
        << "<th width='10%'>ExpMA12wk</th>"
        << "<th width='10%'>ExpMA50wk</th>"
        << "<th width='10%'>seasonratio</th>"
        << "</tr></thead><tbody>";
 
 
    for (const auto& data : lstData) {
        ss << "<tr>"
            << "<td>" << data.stkcode << "</td>"
            << "<td>" << data.stkname << "</td>"
            << "<td>" << data.stknew << "</td>"
            << "<td>" << data.roe << "</td>"
            << "<td>" << data.mgsy << "</td>"
            << "<td>" << data.score << "</td>"
            << "<td>" << data.height << "</td>"
            << "<td>" << data.c2exp12 << "</td>"
            << "<td>" << data.c2exp50 << "</td>"
            << "<td>" << data.c2exp12wk << "</td>"
            << "<td>" << data.c2exp50wk << "</td>"
            << "<td>" << data.seasonratio << "</td>"
            << "</tr>";
    }

    ss << "</tbody></table></body></html>";

    return ss.str();
}

std::string removeHtmlTags(const std::string& html) {
    std::regex tag_re("<[^>]+>"); // 匹配HTML标签的正则表达式
    return std::regex_replace(html, tag_re, ""); // 替换掉所有的HTML标签
}



std::string handleRequest2(const std::string& method, const std::string& uri, const std::string& body, std::vector<TDXDAT2>& lstData) {

    static bool isInit = false;
    if (!isInit) {

        if (!init_thread_mysql_connection("localhost", "admin", "Zls99", "stock", 3306)) {
            return "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nFailed to initialize MySQL connection.";
        }
        isInit = true;
    }

    
    std::unordered_map<std::string, std::string> headers;

   
    std::string responseContent;
    int statusCode = 404;

    if (method == "GET") {
        
        if (uri == "/min") {

            std::ifstream file("c:\\sys\\min.txt");

            if (file.is_open()) {
                statusCode = 200;
                std::cout << "Handling " << method << " request for URI: " << uri << std::endl;
                std::stringstream buffer;
                buffer << file.rdbuf();
                responseContent = "<html><body><p><span style=\"font-size: 12px;\">" + buffer.str() + "</span></p></body></html>";

                file.close();


                headers["Content-Type"] = "text/plain; charset=utf-8";
            }
            else {
                statusCode = 404;
                responseContent = "<html><body><h1>404 Not Found</h1></body></html>";
                headers["Content-Type"] = "text/html; charset=utf-8";
            }
        }


        else
        {
            statusCode = 404;
            responseContent = "<html><body><h1>404 Not Found</h1></body></html>";
            headers["Content-Type"] = "text/html; charset=utf-8";
        }


    }
    else if (method == "POST") {

        std::string dataIdStr = extractJsonField(body, "dataId");  
        int dataId = std::stoi(dataIdStr);  


        std::string sqlresult = "";




        bool brr = getMysqlHtml(dataId, sqlresult);


        if (brr) {

            std::string plain_text = removeHtmlTags(sqlresult);


            std::vector<std::string> matchedNames = findMatchesWithRegex(stkvecs, plain_text);

            if (matchedNames.size() == 0)
            {
                goto POSTFINAL;
            }
            for (const auto& name : matchedNames) {  //stkcode
                if (name.empty())
                {

                    continue;
                }

                TDXDAT2 data;
                data.stkcode = name;

                data.stknew = 0;
                data.roe = 0;
                data.mgsy = 0;
                data.score = 0;
                data.height = 0;
                data.c2exp12 = 0;
                data.c2exp50 = 0;
                data.c2exp12wk = 0;
                data.c2exp50wk = 0;
                data.seasonratio = 0;
                lstData.push_back(data);
            }
            for (size_t i = 0; i < lstData.size(); ++i) {
                LPTDXDAT2 data = FetchDataNameFromMySQL(thread_mysql_conn, lstData[i].stkcode);
                if (!data)
                {
                   
                    goto POSTFINAL;
                }
              
                lstData[i].stkname = data->stkname;
                lstData[i].stknew = data->stknew;
                lstData[i].mgsy = data->mgsy;
                lstData[i].roe = data->roe;
                lstData[i].height = data->height;
                lstData[i].score = data->score;
                lstData[i].c2exp12 = data->c2exp12;
                lstData[i].c2exp50 = data->c2exp50;
                lstData[i].c2exp12wk = data->c2exp12wk;
                lstData[i].c2exp50wk = data->c2exp50wk;
                lstData[i].seasonratio = data->seasonratio;
             
                free(data);
            }
        }
        else
        {
            statusCode = 404;
            responseContent = "<html><body><h1>404 Not Found</h1></body></html>";
            headers["Content-Type"] = "text/html; charset=utf-8";

            std::string response = "HTTP/1.1 " + std::to_string(statusCode) + (statusCode == 200 ? " OK" : " Not Found") + "\r\n";
            for (const auto& header : headers) {
                response += header.first + ": " + header.second + "\r\n";
            }
            response += "\r\n" + responseContent;

            return response;
        }


        statusCode = 200;


        responseContent = generateHtmlFromLstData(lstData);
        headers["Content-Type"] = "text/html; charset=utf-8";

        std::string response = "HTTP/1.1 " + std::to_string(statusCode) + (statusCode == 200 ? " OK" : " Not Found") + "\r\n";
        for (const auto& header : headers) {
            response += header.first + ": " + header.second + "\r\n";
        }
        response += "\r\n" + responseContent;

        return response;

       
    }

POSTFINAL:

 
    headers["Content-Type"] = "text/html; charset=utf-8";
    
    headers["Access-Control-Allow-Origin"] = "*";

    
    if (method == "OPTIONS") {
        headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS";
        headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization";
        responseContent = "";  
        statusCode = 204;  
    }

    
    std::string response = "HTTP/1.1 " + std::to_string(statusCode) + (statusCode == 200 ? " OK" : " Not Found") + "\r\n";
    for (const auto& header : headers) {
        response += header.first + ": " + header.second + "\r\n";
    }
    response += "\r\n" + responseContent;

    return response;
}



void handleClient(SOCKET client_socket, SSL_CTX* ctx) {

    static bool isInit = false;
    if (!isInit) {
        if (!init_thread_mysql_connection("localhost", "admin", "Zls_", "stock", 3306)) {
            return;
        }
        isInit = true;
    }

    SSL* ssl;
    char buffer[1024];
    std::string request;
    BIO* bio = BIO_new(BIO_s_mem());

    ssl = SSL_new(ctx);  
    SSL_set_fd(ssl, client_socket);  

    if (SSL_accept(ssl) <= 0) {  
        ERR_print_errors(bio);  

   
        char errBuffer[1024];
        std::ostringstream oss;
        int len;
        while ((len = BIO_read(bio, errBuffer, sizeof(errBuffer))) > 0) {
            oss.write(errBuffer, len);
        }
        BIO_free(bio);

        std::ofstream logFile("c:\\sys\\error.log", std::ios::app);
        if (logFile.is_open()) {
            logFile << "SSL accept failed: " << oss.str() << "\n";
            logFile.close();
        }
        else {
            std::cerr << "Failed to open error log file." << std::endl;
        }
    }
    else {
        std::cerr << "Failed to create BIO for error logging." << std::endl;
    }


    while (true) {
        int n = SSL_read(ssl, buffer, sizeof(buffer) - 1);  
        if (n <= 0) {
            break;
        }

        buffer[n] = '\0';
        request.append(buffer, n);

        std::cout << "Received data: " << request << std::endl;

        size_t pos = request.find('\n');
        if (pos == std::string::npos) {
            continue; 
        }

        std::istringstream req_line(request.substr(0, pos));
        std::string method, uri, version;
        if (!(req_line >> method >> uri >> version)) {
            std::cerr << "Invalid HTTP request line." << std::endl;
            break;
        }

        pos = request.find("\r\n\r\n");
        if (pos == std::string::npos) {
            continue; 
        }

        std::string body = request.substr(pos + 4);

        std::vector<TDXDAT2> lstData;

        std::string response = handleRequest2(method, uri, body, lstData);

        _CrtDumpMemoryLeaks(); 

        SSL_write(ssl, response.c_str(), response.length()); 

        cleanup_thread_mysql_connection();

        if (method != "OPTIONS") {
            SSL_shutdown(ssl); 
            SSL_free(ssl); 
            closesocket(client_socket); 
            break;
        }
    }
}

std::string extractJsonField(const std::string& jsonStr, const std::string& field) {
    size_t startPos = jsonStr.find("\"" + field + "\"");
    if (startPos == std::string::npos) return ""; 

    startPos = jsonStr.find(":", startPos);
    if (startPos == std::string::npos) return "";

    startPos++;  
    bool inQuotes = false;
    std::string value;

 
    for (size_t i = startPos; i < jsonStr.length(); ++i) {
        char c = jsonStr[i];
        if (c == '"') {
            if (!inQuotes) inQuotes = true;
            else if (i > 0 && jsonStr[i - 1] != '\\') inQuotes = false;
        }
        if (!inQuotes && (c == ',' || c == '}')) break;  
        if ((inQuotes || (isdigit(c) || c == '-' || c == '.')) && i >= startPos) {
            value += c;
        }
    }

    return value;
}

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>



int main()
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    bool arbb = FetchDataVec();
    if (!arbb)
    {
        std::cerr << "init vec err." << std::endl;
        exit(1);
    }
    init_openssl(); // 初始化OpenSSL
    SSL_CTX* ctx = create_context();
    configure_context(ctx);

    WSADATA wsdata;
    SOCKET s_server, s_accept;
    SOCKADDR_IN server_addr;

    
    if (WSAStartup(MAKEWORD(2, 2), &wsdata)) {
        std::cerr << "Failed to initialize WinSock." << std::endl;
        cleanup_openssl();
        return 1;
    }

    s_server = socket(PF_INET, SOCK_STREAM, 0);
    if (s_server == INVALID_SOCKET) {
        std::cerr << "Failed to create socket." << std::endl;
        WSACleanup();
        cleanup_openssl();
        return 1;
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8226);
    if (inet_pton(AF_INET, "127.0.0.1", &(server_addr.sin_addr)) != 1) {
        std::cerr << "Failed to convert IP address." << std::endl;
        closesocket(s_server);
        WSACleanup();
        cleanup_openssl();
        return 1;
    }

    if (bind(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR ||
        listen(s_server, 1) == SOCKET_ERROR) {
        std::cerr << "Binding or listening failed." << std::endl;
        closesocket(s_server);
        WSACleanup();
        cleanup_openssl();
        return 1;
    }

    while (true) {
        sockaddr_in accept_addr;
        int len = sizeof(SOCKADDR);
        s_accept = accept(s_server, (SOCKADDR*)&accept_addr, &len);
        if (s_accept == SOCKET_ERROR) {
            std::cerr << "Accept failed." << std::endl;
            continue;
        }

        std::thread client_thread(handleClient, s_accept, ctx);
        client_thread.detach(); 
    }
    _CrtDumpMemoryLeaks(); 

    closesocket(s_server);
    WSACleanup();
    SSL_CTX_free(ctx); 
    cleanup_openssl();

   

    return 0;
}

HTML 控制台输出:

/htmljson:1 
            
            

          
            
            
           POST https://47.120.18.2/htmljson 404 (Not Found)
loadJson @ index-CofVbsKq.js:2
(匿名) @ index-CofVbsKq.js:2
index-CofVbsKq.js:2 
            



弹窗报内存泄露:
corecrt_internal_strtox.h line 1772 expression: _p!=nullptr

  • 写回答

1条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2025-04-05 16:32
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 关键点分析
      - 代码片段中thread_local MYSQL* thread_mysql_conn = nullptr;声明了一个线程局部变量,用于存储线程特定的MySQL连接指针,目前看起来没有明显的内存泄露风险。
      - 而struct stkvec的定义不完整,char s后面缺少内容,这可能导致结构体定义错误,影响后续使用该结构体时的内存管理。
    2. 解决方案
      - 首先完善struct stkvec的定义。例如,假设完整的结构体定义如下:
    struct stkvec {
        char stkcode[7];  
        char s[10]; // 假设补充一个字符数组成员
    };
    
    • 对于thread_local MYSQL* thread_mysql_conn,在程序结束时,线程局部变量会自动被销毁。但如果在程序运行过程中,没有正确地关闭和释放通过thread_mysql_conn连接的MySQL资源,可能会导致内存泄露。例如,当程序结束时,MySQL连接没有被关闭:
    // 假设在某个函数中使用thread_mysql_conn
    void someFunction() {
        if (thread_mysql_conn == nullptr) {
            thread_mysql_conn = mysql_init(nullptr);
            if (!mysql_real_connect(thread_mysql_conn, "host", "user", "password", "database", 0, nullptr, 0)) {
                std::cerr << "MySQL connect failed: " << mysql_error(thread_mysql_conn) << std::endl;
                return;
            }
        }
        // 后续执行MySQL操作
        //...
        // 程序结束时没有关闭连接
    }
    
    • 要避免这种情况,应该在合适的地方关闭MySQL连接,例如在程序退出时或者线程结束时:
    // 假设在程序退出函数中关闭连接
    void onProgramExit() {
        if (thread_mysql_conn!= nullptr) {
            mysql_close(thread_mysql_conn);
            thread_mysql_conn = nullptr;
        }
    }
    
    1. 多种解决方案优缺点
      - 优点
      • 正确关闭MySQL连接的方式简单直接,能够确保资源被释放,避免内存泄露。
      • 缺点
      • 需要在程序的合适位置添加关闭连接的代码,如果忘记添加或者程序异常退出时没有执行到关闭连接的代码,仍然可能导致内存泄露。可以考虑使用智能指针来管理MySQL连接,例如std::unique_ptr<MYSQL, decltype(&mysql_close)> thread_mysql_conn(nullptr, mysql_close);,这样在智能指针析构时会自动调用mysql_close,能更可靠地管理资源。
    2. 总结
      - 首先要确保结构体定义完整,避免因定义不完整导致后续使用错误。
      - 对于线程局部的MySQL连接指针,要注意在程序合适位置正确关闭连接,防止内存泄露。可以借助智能指针来更方便且可靠地管理MySQL连接资源。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月13日
  • 已采纳回答 4月5日
  • 创建了问题 4月5日