服务器vector内存泄漏排查过程

        在开发过程中出现内存泄漏反复排查具体原因,终于定位到是因为vector操作不当引起内存泄漏,再次记录此次过程

struct FieldInfo {

    std::string value;

    std::vector<std::string> multi_value;

    bool valid_discrete_feature_ = false;

    FieldInfo() {

    }

    FieldInfo(std::string& single_value) : value(single_value) {

    }

};

std::vector<FieldInfo> ad_fields(FLAGS_max_feature_count); (FLAGS_max_feature_count = 1024)

vector主要就是保存上面的结构体,上面结构体相对简单,主要是给value赋值,代码如下:

ad_fields[FIELD_INDUSTRY_LEVEL1_ID].value = location_result.industry_level1_id;

(直接使用ad_fields位置 直接赋值给其内部结构体value)

ad_fields向量需要循环引用赋值(具体是业务需要对ad级别特征

<think>我们需要使用WinHTTP库来发送一个multipart/form-data请求,其中包含两个PDF文件。步骤如下:1.初始化WinHTTP。2.创建一个会话。3.打开一个请求(连接到目标服务器)。4.设置请求头为multipart/form-data,并生成一个边界字符串。5.构建表单数据体,将两个PDF文件作为二进制数据附加到请求体中。6.发送请求。7.接收响应。注意:由于是HTTPS,我们需要指定端口为443,并设置WINHTTP_FLAG_SECURE。我们将按照以下步骤构建请求体:-使用一个唯一的边界字符串(boundary)分隔表单中的不同部分。-每个部分包含一个Content-Disposition头部,指定字段名和文件名,以及Content-Type为application/pdf。-然后紧接着是文件的二进制数据。请求体结构示例:--boundaryContent-Disposition:form-data;name="file1";filename="file1.pdf"Content-Type:application/pdf[PDF文件1的二进制数据]--boundaryContent-Disposition:form-data;name="file2";filename="file2.pdf"Content-Type:application/pdf[PDF文件2的二进制数据]--boundary--我们将动态构建这个请求体,因为文件内容可能很大,我们不会一次性将所有内容读入内存,但为了简单起见,这里假设文件不是特别大,我们可以一次性读取。如果文件很大,应该分块读取并发送。但是,WinHTTP允许我们使用WinHttpWriteData分段发送数据。然而,为了简化,我们一次性构建整个请求体。步骤:1.读取两个PDF文件到内存中。2.构建整个请求体(包括边界和头部)到一个缓冲区。3.计算整个请求体的大小。但是注意:如果文件很大,一次性读取可能占用过多内存。因此,我们可以采用另一种方式:先发送边界和头部,然后发送文件数据,再发送下一个边界和头部以及第二个文件,最后发送结束边界。这样内存占用较小。这里我们为了清晰,先使用一次性构建的方法。如果文件很大,我们可以分段构建并发送,但代码会复杂一些。我们这里假设文件不是特别大。另外,边界字符串需要是唯一的,通常使用一串随机字符。这里我们可以使用一个简单的边界,比如"----WebKitFormBoundary7MA4YWxkTrZu0gW"(示例),但实际中应该生成一个唯一的。我们使用一个简单的边界,但确保它在文件内容中不会出现。通常,使用一个足够长的随机字符串可以避免。代码步骤:1.初始化WinHttp。2.创建会话和连接。3.创建请求(使用POST方法)。4.读取两个PDF文件到内存。5.构建请求体(包括边界和文件数据)。6.设置请求头:Content-Type为multipart/form-data,并指定边界。7.发送请求,并写入请求体。8.接收响应并读取响应数据。9.清理资源。注意:错误处理很重要。下面是一个示例代码:</think>在 C++ 中使用 WinHTTP 通过 `multipart/form-data` 格式发送两个 PDF 文件到 HTTPS 服务器的完整实现如下。此代码包含详细的错误处理和内存管理: ```cpp #include <windows.h> #include <winhttp.h> #include <iostream> #include <vector> #include <fstream> #include <sstream> #include <cassert> #pragma comment(lib, "winhttp.lib") // 读取文件内容到字节向量 std::vector<BYTE> ReadFileToBuffer(const wchar_t* filePath) { std::ifstream file(filePath, std::ios::binary | std::ios::ate); if (!file) { throw std::runtime_error("无法打开文件"); } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); std::vector<BYTE> buffer(size); if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) { throw std::runtime_error("读取文件失败"); } return buffer; } // 生成多部分表单边界字符串 std::wstring GenerateBoundary() { return L"------------------------" + std::to_wstring(GetTickCount64()); } // 构建 multipart/form-data 请求体 std::vector<BYTE> BuildMultipartBody( const std::vector<std::wstring>& fieldNames, const std::vector<std::wstring>& filePaths, const std::vector<std::wstring>& fileNames, const std::wstring& boundary) { assert(fieldNames.size() == filePaths.size() && filePaths.size() == fileNames.size()); std::wstringstream bodyStream; // 添加每个文件部分 for (size_t i = 0; i < filePaths.size(); ++i) { auto fileData = ReadFileToBuffer(filePaths[i].c_str()); bodyStream << L"--" << boundary << L"\r\n" << L"Content-Disposition: form-data; " << L"name=\"" << fieldNames[i] << L"\"; " << L"filename=\"" << fileNames[i] << L"\"\r\n" << L"Content-Type: application/pdf\r\n\r\n"; // 将文本头部转换为二进制 std::wstring headerPart = bodyStream.str(); std::vector<BYTE> bodyBuffer( reinterpret_cast<const BYTE*>(headerPart.c_str()), reinterpret_cast<const BYTE*>(headerPart.c_str() + headerPart.size() * sizeof(wchar_t)) ); // 添加文件二进制数据 bodyBuffer.insert(bodyBuffer.end(), fileData.begin(), fileData.end()); // 添加部分分隔符 std::wstring partEnd = L"\r\n"; bodyBuffer.insert(bodyBuffer.end(), reinterpret_cast<const BYTE*>(partEnd.c_str()), reinterpret_cast<const BYTE*>(partEnd.c_str() + partEnd.size() * sizeof(wchar_t)) ); bodyStream.str(L""); // 重置流 bodyStream.clear(); } // 添加结束边界 std::wstring finalBoundary = L"--" + boundary + L"--\r\n"; std::vector<BYTE> finalBuffer( reinterpret_cast<const BYTE*>(finalBoundary.c_str()), reinterpret_cast<const BYTE*>(finalBoundary.c_str() + finalBoundary.size() * sizeof(wchar_t)) ); return finalBuffer; } void SendMultipartRequest() { const wchar_t* server = L"example.com"; const wchar_t* path = L"/upload"; const DWORD port = 443; // 配置要发送的文件 std::vector<std::wstring> fieldNames = { L"document1", L"document2" }; std::vector<std::wstring> filePaths = { L"C:\\path\\to\\file1.pdf", L"C:\\path\\to\\file2.pdf" }; std::vector<std::wstring> fileNames = { L"report1.pdf", L"report2.pdf" }; std::wstring boundary = GenerateBoundary(); std::vector<BYTE> requestBody = BuildMultipartBody(fieldNames, filePaths, fileNames, boundary); // 初始化 WinHTTP HINTERNET hSession = WinHttpOpen( L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ); if (!hSession) { std::cerr << "WinHttpOpen 错误: " << GetLastError() << std::endl; return; } // 设置超时(可选) WinHttpSetTimeouts(hSession, 60000, 60000, 30000, 30000); // 建立 HTTPS 连接 HINTERNET hConnect = WinHttpConnect( hSession, server, port, 0 ); if (!hConnect) { std::cerr << "WinHttpConnect 错误: " << GetLastError() << std::endl; WinHttpCloseHandle(hSession); return; } // 创建请求 HINTERNET hRequest = WinHttpOpenRequest( hConnect, L"POST", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE ); if (!hRequest) { std::cerr << "WinHttpOpenRequest 错误: " << GetLastError() << std::endl; WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return; } // 设置 Content-Type 头 std::wstring contentType = L"multipart/form-data; boundary=" + boundary; if (!WinHttpAddRequestHeaders( hRequest, contentType.c_str(), -1L, WINHTTP_ADDREQ_FLAG_ADD )) { std::cerr << "WinHttpAddRequestHeaders 错误: " << GetLastError() << std::endl; } // 发送请求 if (!WinHttpSendRequest( hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, requestBody.data(), static_cast<DWORD>(requestBody.size()), static_cast<DWORD>(requestBody.size()), 0 )) { std::cerr << "WinHttpSendRequest 错误: " << GetLastError() << std::endl; goto cleanup; } // 结束请求发送 if (!WinHttpReceiveResponse(hRequest, NULL)) { std::cerr << "WinHttpReceiveResponse 错误: " << GetLastError() << std::endl; goto cleanup; } // 处理响应(示例:读取前1024字节) DWORD size = 0; WinHttpQueryHeaders( hRequest, WINHTTP_QUERY_STATUS_CODE, NULL, &size, WINHTTP_NO_HEADER_INDEX ); std::vector<wchar_t> statusBuf(size / sizeof(wchar_t)); WinHttpQueryHeaders( hRequest, WINHTTP_QUERY_STATUS_CODE, NULL, statusBuf.data(), &size, 0 ); std::wcout << L"服务器响应: " << statusBuf.data() << std::endl; cleanup: WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); } int main() { try { SendMultipartRequest(); } catch (const std::exception& e) { std::cerr << "错误: " << e.what() << std::endl; return 1; } return 0; } ``` ### 关键点解释: 1. **多部分表单构建**: - 使用随机生成的边界分隔符(`GenerateBoundary`) - 每个文件部分包含: - `Content-Disposition` 指定字段名和文件名 - `Content-Type: application/pdf` 声明文件类型 - 文件二进制数据 - 结尾使用 `--boundary--` 表示结束 2. **WinHTTP 工作流程**: - `WinHttpOpen()`:初始化会话 - `WinHttpConnect()`:连接到目标服务器 - `WinHttpOpenRequest()`:创建 HTTPS 请求(`WINHTTP_FLAG_SECURE`) - `WinHttpAddRequestHeaders()`:设置 `multipart/form-data` 内容类型 - `WinHttpSendRequest()`:发送构建好的请求体 - `WinHttpReceiveResponse()`:接收服务器响应 3. **文件处理**: - 使用二进制模式读取 PDF 文件(`ReadFileToBuffer`) - 正确处理宽字符与二进制数据的转换 - 内存管理确保无泄漏 4. **安全特性**: - HTTPS 连接自动处理证书验证 - 超时设置防止无限等待 - 错误检查覆盖所有 WinHTTP 操作 5. **边界生成**: - 使用系统时间戳确保唯一性 - 符合 RFC 7578 标准格式 ### 常见问题排查: 1. 文件读取失败:检查路径权限和文件是否存在 2. 连接失败:验证服务器域名和端口(443) 3. 证书错误:需处理服务器证书验证(此处使用系统默认) 4. 内存不足:大文件需分块读取发送(当前代码适合中等文件)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值