当前位置: 首页 > article >正文

【C++接入大模型】WinHTTP类封装:实现对话式大模型接口访问

一、类设计概述

近期准备用C++做一些大预言模型方面的开发,先期计划实现C++调用公共的大模型Web接口,因为之前没做过C++的Web开发,经验少,所以对比了一些主流的框架,包括实际测试验证。以下是Windows平台下主流C++ HTTP库的对比分析:

库名称内置支持第三方依赖HTTPS支持API复杂度跨平台社区活跃度典型应用场景
WinHTTP✅ 是(Windows SDK)无(自动处理SSL/TLS)✅ 原生支持(无需OpenSSL)中等❌ 仅Windows中等系统级应用、快速集成、Windows专属开发
libcurl❌ 需手动集成需OpenSSL/zlib等✅ 依赖第三方库配置✅ 是跨平台项目、复杂协议需求
libhv❌ 需手动集成无(内置SSL支持)✅ 需编译时启用中等✅ 是中等高性能网络服务、异步IO场景
Boost.Beast❌ 需Boost库需OpenSSL✅ 需手动配置✅ 是现代C++项目、需要高度定制化
cpp-netlib❌ 需手动集成需Boost/Asio等✅ 需依赖项支持✅ 是传统企业级应用、遗留系统维护
Poco❌ 需手动集成需OpenSSL✅ 需手动配置中等✅ 是中等综合性框架需求、企业级开发
Crow❌ 需手动集成无(仅HTTP)❌ 无原生支持✅ 是轻量级Web服务、快速原型开发

转了一圈,最终选择了Windows原生WinHTTP API实现。

选型原因分析

  1. 内置支持与零配置优势

    • WinHTTP直接集成于Windows系统,无需额外安装或配置OpenSSL等依赖,避免了证书链、动态库路径等复杂问题。对于Windows专属应用,可直接调用winhttp.lib,实现"开箱即用",也支持流式接口。
  2. 简化HTTPS开发

    • WinHTTP自动处理TLS/SSL握手和证书验证(通过SECURITY_FLAG_IGNORE_*标志控制),开发者无需手动管理加密套件或协议版本,显著降低HTTPS开发门槛。
  3. 资源占用与性能平衡

    • 相比libhv或Boost.Beast等跨平台库,WinHTTP在Windows环境下表现出更优的资源利用率,尤其适合对内存占用敏感的系统工具或后台服务。
  4. API复杂度可控

    • 虽然WinHTTP API较为底层,但通过封装(如您提供的SimpleHttp类)可屏蔽复杂性,同时保留对请求头、超时等关键参数的控制能力。
  5. 企业级安全合规

    • WinHTTP通过微软签名验证,符合Windows安全合规要求,适合金融、政务等对供应链安全敏感的场景。

SimpleHttp核心特性

SimpleHttp 是基于 Windows WinHTTP API 封装的 C++ HTTP 客户端类,支持同步/异步 HTTP/HTTPS 请求,提供流式数据处理能力。特性包括:

  • 自适应HTTP/HTTPS协议
  • 支持流式传输(Streaming)
  • 线程安全的数据队列
  • 异常安全的资源管理
  • 符合C++20标准的现代语法

类接口说明

公共接口说明
1. 构造函数
SimpleHttp(const std::string& home, bool https = false);
  • 功能:初始化 WinHTTP 会话,设置基地址和协议类型
  • 参数
    • home:服务器基地址(如 "api.example.com"
    • https:是否使用 HTTPS(默认 false
  • 异常:会话初始化失败时抛出 std::runtime_error
2. 析构函数
~SimpleHttp();
  • 功能:释放所有资源,确保流式线程安全退出
  • 行为
    • 终止流式接收线程(若有)
    • 关闭所有 WinHTTP 句柄
3. GET 请求
int Get(const std::string& upath, std::string& resp, bool stream = false);
  • 功能:发起 GET 请求
  • 参数
    • upath:接口路径(自动拼接基地址)
    • resp:同步模式下存储完整响应
    • stream:是否启用流式处理(默认 false
  • 返回值
    • 0:成功(流式请求立即返回)
    • -1:失败(异常抛出前返回)
  • 异常:网络错误或 HTTP 状态码非 200 时抛出 std::runtime_error
4. POST 请求
int Post(const std::string& upath, const std::string& para, std::string& resp, bool stream = false);
  • 功能:发起 POST 请求
  • 参数
    • upath:接口路径
    • para:JSON 格式请求体
    • resp:同步模式下存储完整响应
    • stream:是否启用流式处理
  • 返回值:同 Get() 方法
  • 默认头:自动添加 Content-Type: application/json(可覆盖)
5. 流式响应获取
int TryFetchResp(std::string& resp);
  • 功能:轮询获取流式数据块
  • 参数resp 存储当前数据块
  • 返回值
    • >0:数据长度
    • 0:流结束
    • -1:暂无数据
  • 线程安全:通过互斥锁保护队列
6. 设置请求头
void SetHeaders(const std::unordered_map<std::string, std::string>& headers);
  • 功能:批量设置请求头
  • 参数:键值对映射(如 { {"Authorization", "Bearer token"} }
  • 合并策略:相同头字段自动合并(WINHTTP_ADDREQ_FLAG_COALESCE

异常处理

  • 抛出类型std::runtime_error
  • 典型场景
    • 网络连接失败(如 DNS 解析错误)
    • 请求创建失败
    • HTTP 状态码非 200
    • 流式线程异常终止

流式处理工作流程

  1. 调用 Get()/Post() 时设置 stream = true
  2. 轮询调用 TryFetchResp() 获取数据
  3. 当返回 0 时终止循环

示例代码

SimpleHttp client("https://api.example.com", true);
client.Get("/stream", response, true);std::string chunk;
do {int size = client.TryFetchResp(chunk);if (size > 0) Process(chunk);else std::this_thread::sleep_for(std::chrono::milliseconds(100));
} while (size != 0);

实现细节

  • 线程管理:流式请求启动独立线程持续接收数据
  • 资源释放:析构函数确保线程和句柄正确关闭
  • 编码转换:内部使用 UTF-8 处理字符串(wstring2s/string2w

限制与注意事项

  1. 仅支持 Windows 平台(依赖 WinHTTP)
  2. 流式请求需手动管理生命周期
  3. HTTPS 默认忽略证书错误(生产环境需修改安全标志)

版本兼容性

  • Windows SDK:最低支持 Windows 7/Server 2008 R2
  • 编译器:需支持 C++17

二、核心函数深度分析

封装的类比较简单,支持GET和POST请求,支持流式接口,下面对封装的每个部分逐一展开说明。

1. 构造函数

SimpleHttp(const std::string& home, bool https = false)

实现要点:

  • 会话初始化:通过WinHttpOpen创建持久化会话,设置用户代理为"SimpleHttp/1.0"
  • 超时控制:统一设置5秒超时(连接/发送/接收/空闲)
  • 异常处理:会话创建失败时抛出runtime_error,包含系统错误码
  • 协议识别:通过_isHttps标记自动区分协议类型

设计考量:

  • 使用默认代理配置(WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)提高兼容性
  • 零初始化参数(WINHTTP_NO_PROXY_NAME)避免冗余配置

2. 析构函数

~SimpleHttp()

资源管理:

  • 线程安全终止:通过原子变量_streamActive控制流式线程退出
  • 句柄清理
    • 顺序关闭请求→连接→会话句柄
    • 使用RAII模式确保资源释放

异常防御:

  • joinable()检查避免二次join导致崩溃
  • 线程终止前设置_streamActive=false防止死锁

3. Get请求

int Get(const std::string& upath, std::string& resp, bool stream = false)

工作流程:

  1. 调用SendRequest发起GET请求
  2. 根据stream参数选择同步/异步模式
  3. 同步模式直接返回完整响应
  4. 异步模式启动子线程持续接收数据

参数设计:

  • upath:URL路径自动拼接基地址
  • stream:控制响应处理模式(内存缓冲/流式队列)

4. Post请求

int Post(const std::string& upath, const std::string& para, std::string& resp, bool stream = false)

增强特性:

  • 自动设置Content-Type为application/json(未指定时)
  • 支持任意格式POST数据(通过para参数)
  • 数据长度自动计算(postData.size()

安全机制:

  • 使用WINHTTP_FLAG_REFRESH强制获取最新资源
  • HTTPS请求自动忽略证书错误(测试环境适用)

5. 流式响应获取

int TryFetchResp(std::string& resp)

队列管理:

  • 互斥锁保护的_datas队列
  • 三态返回值设计:
    • >0:有效数据长度
    • 0:流结束标记
    • -1:暂无数据

性能优化:

  • 队列首部数据优先出队(O(1)时间复杂度)
  • 空队列时立即返回避免阻塞

6. 请求头设置

void SetHeaders(const std::unordered_map<std::string, std::string>& headers)

头处理机制:

  • 使用WINHTTP_ADDREQ_FLAG_COALESCE自动合并重复头
  • 支持批量添加/覆盖现有头
  • 保留默认Content-Type设置

实现细节:

  • 字符串转换使用UTF-8编码
  • 头格式验证(自动添加冒号分隔符)

三、关键私有方法

1. 核心请求处理

int SendRequest(const std::wstring& method, ...)

多阶段处理:

  1. 连接建立WinHttpConnect创建目标服务器连接
  2. 请求创建WinHttpOpenRequest配置请求方法/路径
  3. 安全设置:HTTPS请求忽略证书错误
  4. 头注入:遍历_headers容器添加自定义头
  5. 数据发送WinHttpSendRequest传输请求体
  6. 响应处理:同步模式直接读取,异步模式启动接收线程

异常处理:

  • 每个WinAPI调用后立即检查返回值
  • 使用结构化异常处理(SEH)捕获系统级错误

2. 流式接收器

void StreamReceiver(HINTERNET hConnect, HINTERNET hRequest)

并发设计:

  • 使用原子变量_streamActive控制循环
  • 独立线程持续调用WinHttpReadData
  • 数据块即时推入线程安全队列

资源管理:

  • 函数退出时自动关闭连接/请求句柄
  • 异常传播前确保资源释放

3. 字符串转换

std::string wstring2s(const std::wstring& wstr)
std::wstring string2w(const std::string& str)

编码转换:

  • 基于Windows API的UTF-8转换
  • 预分配目标缓冲区优化性能
  • 空字符串快速路径

四、辅助函数解析

1. 全局替换函数

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to)

实现特点:

  • 原地修改(接收值拷贝)
  • 处理重叠替换问题(pos递增策略)
  • 空模式保护避免死循环

2. JSON内容提取

std::string ExtractContent(std::string& resp)

解析逻辑:

  • 基于特征字符串定位(“content”:")
  • 支持转义字符处理(\n, \r, ", \)
  • 修改输入字符串实现流式解析

健壮性设计:

  • 非规范JSON容错处理
  • 内存安全(范围检查)

五、代码示例说明

1. 同步请求示例

SimpleHttp client("api.example.com", true);
std::string response;
client.Get("/data", response);
  • 即时获取完整响应
  • 适用于小型数据交互

2. 流式处理示例

client.Post("/stream", data, response, true);
while(int size = client.TryFetchResp(chunk)) {if(size > 0) process(chunk);
}
  • 实时处理大文件/持续数据流
  • 减少内存占用(无需完整缓存)

六、问题解决

Q:析构时触发断点

  • 原因:流式线程未正确终止
  • 解决方案:
    ~SimpleHttp() {CancelStream(); // 新增统一清理if(_hSession) WinHttpCloseHandle(_hSession);
    }void CancelStream() {if(_streamActive.exchange(false)) {WinHttpCloseHandle(_hRequest); // 强制终止if(_worker.joinable()) _worker.join();}
    }
    

Q:HTTPS证书错误

  • 解决方案:生产环境应移除证书忽略配置
    if(_isHttps) {DWORD dwFlags = SECURITY_FLAG_SECURE; // 严格验证WinHttpSetOption(...);
    }
    

七、总结

本实现通过封装WinHTTP API,在保持高性能的同时提供了简洁的接口。通过线程安全的流式处理、健壮的错误恢复和现代化的C++特性,适用于需要精细控制HTTP通信的Windows应用场景。未来可通过连接池、异步回调等机制进一步提升性能,满足更复杂的企业级需求。

八、完整代码

#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <tchar.h>
#include <mutex>
#include <atomic>
#include <thread>#pragma comment(lib, "winhttp.lib")
#include <strsafe.h>/// <summary>
/// 简单的HTTP类,自动支持http和https请求
/// 也支持流式处理,此时结果先缓存到队列,需主动调用TryFetchResp去轮询结果
/// </summary>
class SimpleHttp
{
public:SimpleHttp(const std::string& home, bool https = false) :_strBaseUrl(home), _isHttps(https){// 初始化WinHTTP会话 [[1]][[2]]_hSession = WinHttpOpen(L"SimpleHttp/1.0",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0);if (!_hSession) {throw std::runtime_error("Failed to initialize WinHTTP session: " + GetLastError());}// 设置默认超时(5秒)DWORD timeout = 5000;WinHttpSetTimeouts(_hSession, timeout, timeout, timeout, timeout);}~SimpleHttp(){if (_worker.joinable()){_streamActive = false;_worker.join();}if (_hSession) WinHttpCloseHandle(_hSession);}/// <summary>/// 发起GET请求/// </summary>/// <param name="upath">接口名</param>/// <param name="resp">非流式请求时接收应答数据</param>/// <param name="stream">是否为流式请求</param>/// <returns></returns>int Get(const std::string& upath, std::string& resp, bool stream = false){return SendRequest(L"GET", upath, "", resp, stream);}/// <summary>/// /// </summary>/// <param name="upath">接口名</param>/// <param name="para">JSON请求参数</param>/// <param name="resp">非流式请求时接收应答数据</param>/// <param name="stream">是否为流式请求</param>/// <returns></returns>int Post(const std::string& upath, const std::string& para, std::string& resp, bool stream = false){return SendRequest(L"POST", upath, para, resp, stream);}/// <summary>/// 获取流式结果/// </summary>/// <param name="resp"></param>/// <returns>返回本次数据包大小,等于0表示数据包接收完成,-1表示没数据</returns>int TryFetchResp(std::string& resp){std::lock_guard<std::mutex> guard(_mtxDatas);if (_datas.empty()){return (_streamActive ? -1 : 0);}resp = _datas[0];_datas.erase(_datas.begin());return static_cast<int>(resp.size());}/// <summary>/// 设置请求头/// </summary>/// <param name="headers"></param>void SetHeaders(const std::unordered_map<std::string, std::string>& headers){for (auto& e : headers){_headers[e.first] = e.second;}}protected:/// <summary>/// 写入接收数据/// </summary>/// <param name="dat"></param>void Push(const std::string& dat){std::lock_guard<std::mutex> guard(_mtxDatas);if(!dat.empty()) _datas.push_back(dat);}private:int SendRequest(const std::wstring& method, const std::string& upath, const std::string& postData, std::string& resp, bool stream) {DWORD dwSize = 0;DWORD dwDownloaded = 0;LPSTR pszOutBuffer;BOOL bResults = FALSE;HINTERNET hConnect = nullptr;HINTERNET hRequest = nullptr;try {// 创建连接hConnect = WinHttpConnect(_hSession,string2w(_strBaseUrl).c_str(),INTERNET_DEFAULT_PORT,0);if (!hConnect) throw std::runtime_error("Connection failed");// 创建请求hRequest = WinHttpOpenRequest(hConnect,method.c_str(), string2w(upath).c_str(),nullptr, WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,(_isHttps ? (WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH) : 0));if (!hRequest) throw std::runtime_error("Request creation failed");// 设置安全选项(忽略证书错误)if (_isHttps){DWORD dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA |SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));}// 设置请求头SetHeaders(hRequest);// 发送请求bResults = WinHttpSendRequest(hRequest,WINHTTP_NO_ADDITIONAL_HEADERS,0,(LPVOID)postData.c_str(),(DWORD)postData.size(),(DWORD)postData.size(),0);if (!bResults) throw std::runtime_error("Send request failed");// 接收响应if (!WinHttpReceiveResponse(hRequest, nullptr)){throw std::runtime_error("Receive response failed");}// 获取状态码 [[10]]DWORD dwStatusCode = 0;DWORD dwSize = sizeof(dwStatusCode);WinHttpQueryHeaders(hRequest,WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,WINHTTP_HEADER_NAME_BY_INDEX, &dwStatusCode,&dwSize,WINHTTP_NO_HEADER_INDEX);if (dwStatusCode != 200) {throw std::runtime_error("HTTP error: " + std::to_string(dwStatusCode));}// 流式子线程处理if (stream){_streamActive = true;_worker = std::thread(&SimpleHttp::StreamReceiver, this, hConnect, hRequest);return 0; // 立即返回}// 处理响应数据std::string buffer;do {dwSize = 0;if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize <= 0) break;size_t nRecv = dwSize;pszOutBuffer = new char[nRecv + 1];ZeroMemory(pszOutBuffer, nRecv + 1);if (WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)){buffer.append(pszOutBuffer, dwDownloaded);}delete[] pszOutBuffer;} while (dwSize > 0);resp = buffer;return 0;}catch (const std::exception& e) {if (hRequest) WinHttpCloseHandle(hRequest);if (hConnect) WinHttpCloseHandle(hConnect);throw std::runtime_error("WinHTTP Error: " + std::string(e.what()) +" [ErrorCode: " + std::to_string(GetLastError()) + "]");return -1;}}/// <summary>/// 流式接收应答/// </summary>void StreamReceiver(HINTERNET hConnect, HINTERNET hRequest){DWORD dwSize = 0;DWORD dwDownloaded = 0;char* pszOutBuffer = nullptr;std::string strErr;try {while (_streamActive) {dwSize = 0;if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize == 0) break;const size_t nRecv = dwSize;pszOutBuffer = new char[nRecv + 1];ZeroMemory(pszOutBuffer, nRecv + 1);if (WinHttpReadData(hRequest, pszOutBuffer, dwSize, &dwDownloaded)){Push(std::string(pszOutBuffer, dwDownloaded));}delete[] pszOutBuffer;}}catch (...) {strErr = "stream recv data error";}// 发送结束标记_streamActive = false;WinHttpCloseHandle(hRequest);WinHttpCloseHandle(hConnect);if (!strErr.empty()){throw std::runtime_error(strErr.c_str());}}/// <summary>/// 设置请求头/// </summary>void SetHeaders(HINTERNET hRequest){// 创建请求后立即设置请求头for (const auto& h : _headers) {std::wstring header = string2w(h.first + ": " + h.second);if (!WinHttpAddRequestHeaders(hRequest,header.c_str(),static_cast<DWORD>(header.length()),WINHTTP_ADDREQ_FLAG_COALESCE)){//throw std::runtime_error("Failed to set header: " + h.first + " [Error: " + std::to_string(GetLastError()) + "]");}}}// std::wstring → std::string (UTF-8)std::string wstring2s(const std::wstring& wstr) {if (wstr.empty()) return {};int len = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), nullptr, 0, nullptr, nullptr);std::string result(len, '\0');WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), (LPSTR)result.data(), len, nullptr, nullptr);return result;}// std::string (UTF-8) → std::wstringstd::wstring string2w(const std::string& str) {if (str.empty()) return {};int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);std::wstring result(len, L'\0');MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), (LPWSTR)result.data(), len);return result;}private:// 是否httpsbool _isHttps{ false };// 基地址std::string _strBaseUrl;// 默认headersstd::unordered_map<std::string, std::string> _headers;// 异步数据std::vector<std::string> _datas;std::mutex _mtxDatas;// WinHttp对象HINTERNET _hSession = nullptr;// 流式操作子线程std::atomic<bool> _streamActive{ false };std::thread _worker;
};std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {if (from.empty()) return str; // 避免死循环[[2]]size_t pos = 0;while ((pos = str.find(from, pos)) != std::string::npos) {str.replace(pos, from.length(), to);pos += to.length();}return str;
}std::string ExtractContent(std::string& resp) {std::vector<std::string> results;std::string key = "\"content\":";size_t pos = 0;while ((pos = resp.find(key, pos)) != std::string::npos) {pos += key.length();// 跳过空白和冒号while (pos < resp.size() && (resp[pos] == ' ' || resp[pos] == ':')) pos++;if (resp[pos] != '"') continue; // 非字符串值跳过size_t start = ++pos;std::string content;// 处理转义字符和双引号while (pos < resp.size()) {char c = resp[pos++];if (c == '"') break;else if (c == '\\' && pos < resp.size()){switch (resp[pos++]){case 'n':c = '\n';break;case '\r':c = '\r';break;case '\\':c = '\\';break;case '"':c = '\"';break;default:pos--;break;}}content += c;}resp = resp.substr(pos);return content;}resp = "";return resp;
}int main()
{int iii = 0;std::cin >> iii;// 请求参数char para[4096] = "{\"stream\" : true,\"model\":\"deepseek-r1-distill-qwen-32b\",\"messages\":[{\"role\":\"user\",\"content\":\"Please help me write a C++ class for parsing XML, with user-friendly interfaces that support XPath and iterative data access.\"}]}";// char para[4096] = "{\"stream\" : true,\"model\":\"deepseek-r1-distill-qwen-32b\",\"messages\":[{\"role\":\"user\",\"content\":\"The prime numbers within 10?\"}]}";auto url = "https://cloud.infini-ai.com/maas/v1/chat/completions";auto api_key = "Bearer sk-************";auto model_name = "deepseek-r1-distill-qwen-32b";SimpleHttp web("cloud.infini-ai.com", true);web.SetHeaders({ { "Content-Type", "application/json" }, { "Authorization", "Bearer sk-daxdj5ksqdc6iuvn" } });std::string resp;web.Post("/maas/v1/chat/completions", para, resp, true);int nRecv = 0;do{nRecv = web.TryFetchResp(resp);if (nRecv > 0){while (!resp.empty()){std::cout << ExtractContent(resp);}}else{std::this_thread::sleep_for(std::chrono::milliseconds(100));}} while (nRecv);return 0;
}

运行结果:
在这里插入图片描述

相关文章:

【C++接入大模型】WinHTTP类封装:实现对话式大模型接口访问

一、类设计概述 近期准备用C做一些大预言模型方面的开发&#xff0c;先期计划实现C调用公共的大模型Web接口&#xff0c;因为之前没做过C的Web开发&#xff0c;经验少&#xff0c;所以对比了一些主流的框架&#xff0c;包括实际测试验证。以下是Windows平台下主流C HTTP库的对…...

MaxEnt物种分布建模全流程;R+ArcGIS+MaxEnt模型物种分布模拟、参数优化方法、结果分析制图与论文写作

融合R语言的MaxEnt模型具有以下具体优势&#xff1a; 数据处理高效便捷 &#x1f4ca;强大的数据预处理功能&#xff1a;R语言提供了丰富的数据处理工具&#xff0c;能够轻松完成数据清洗、筛选、转换等操作&#xff0c;为MaxEnt模型提供高质量的输入数据。 &#x1f310;自动…...

【银河麒麟高级服务器操作系统 】虚拟机运行数据库存储异常现象分析及处理全流程

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…...

python leetcode简单练习(2)

20 有效括号 方法思路 要判断一个仅由括号组成的字符串是否有效&#xff0c;可以使用栈这一数据结构。核心思路是遍历字符串中的每个字符&#xff0c;遇到左括号时压入栈中&#xff0c;遇到右括号时检查栈顶的左括号是否匹配。若匹配则弹出栈顶元素&#xff0c;否则返回false。…...

Android BottomNavigationView 完全自定义指南:图标、文字颜色与选中状态

1. 核心功能概述 通过 Material Design 的 BottomNavigationView&#xff0c;你可以轻松实现以下自定义&#xff1a; ✅ 动态切换选中/默认图标 ✅ 自定义选中与默认文字颜色 ✅ 控制文字显示模式&#xff08;始终显示/仅选中显示/自动隐藏&#xff09; ✅ 添加动画和高级样…...

Kafka 偏移量

在 Apache Kafka 中&#xff0c;偏移量&#xff08;Offset&#xff09;是一个非常重要的概念。它不仅用于标识消息的位置&#xff0c;还在多种场景中发挥关键作用。本文将详细介绍 Kafka 偏移量的核心概念及其使用场景。 一、偏移量的核心概念 1. 定义 偏移量是一个非负整数…...

【NLP】15. NLP推理方法详解 --- 动态规划:序列标注,语法解析,共同指代

动态规划 (Dynamic Programming) 动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种通过将问题分解为较小子问题来优化计算效率的技术。它特别适用于优化最优解问题&#xff0c;比如序列标注&#xff08;sequence tagging&#xff09;这类任务。…...

文件分享系统--开源的可视化文件共享管理工具

家里有公网&#xff0c;经常要发文件给别人&#xff0c;文件几个G发送还要云盘或者倒手一次才行&#xff0c;所以弄了个文件分享系统&#xff0c;这个是用字节的 AI Trae 写的&#xff0c;反正反复折腾还是弄出来了。东西挺好用&#xff0c;可以拖拽多个文件上传也可以手动添加…...

【力扣刷题实战】寻找数组的中心下标

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 力扣题目&#xff1a;寻找数组的中心下标 题目描述 解题思路 问题理解 算法选择 具体思路 解题要点 完整代码&#xff08;C&#xff09; 兄弟们共勉 &#xff01;&#xff01;&#xff01; 每篇前言 博客主页&#…...

LearnOpenGL小练习(QOpenGLWidget版本)

你好&#xff0c;三角形 1.绘制两个彼此相连的三角形 画两个独立的三角形&#xff0c;给出两个三角形顶点&#xff0c;使用GL_TRIANGLES绘图即可。 关键代码 void MyOpenglWgt::initializeGL() {initializeOpenGLFunctions(); // 1. 创建ShaderProgram着色器&#xff1a;加…...

【Easylive】SpringBoot启动类——EasyLiveWebRunApplication

【Easylive】项目常见问题解答&#xff08;自用&持续更新中…&#xff09; 汇总版 这段代码是 Spring Boot 应用的 主启动类&#xff0c;包含了多个关键注解&#xff0c;用于配置和启动整个应用程序。以下是各个部分的详细解析&#xff1a; 1. SpringBootApplication Spri…...

2025 年前端新趋势:拥抱 Web Component 与性能优化

在技术飞速发展的今天&#xff0c;前端开发领域也在持续演进&#xff0c;新的技术和理念不断涌现。2025 年&#xff0c;Web Component 和性能优化无疑是前端开发中值得关注的两大重点&#xff0c;本文将带你深入了解这两大趋势。 Web Component&#xff1a;构建可复用组件的未…...

计算机网络 用deepseek帮助整理的复习资料(一)

### 计算机网络基础知识整理 --- #### **一、网络类型** 1. **局域网 (LAN)** - **定义**&#xff1a;覆盖小范围&#xff08;如家庭、教室、公司&#xff09;。 - **特点**&#xff1a;高带宽、低延迟&#xff0c;设备通过交换机互联。 - **示例**&#xff1…...

基于OpenCV+MediaPipe手部追踪

一、技术栈 1. OpenCV&#xff08;Open Source Computer Vision Library&#xff09; 性质&#xff1a;开源计算机视觉库&#xff08;Library&#xff09; 主要功能&#xff1a; 图像/视频的基础处理&#xff08;读取、裁剪、滤波、色彩转换等&#xff09; 特征检测&#xf…...

美甲预约管理系统基于Spring Boot SSM

目录 摘要 1. 引言‌ 1.1 研究背景与意义 1.2 国内外研究现状 ‌2. 系统需求分析‌ 2.1 功能需求 2.2 非功能需求 ‌3. 系统设计与实现‌ 3.1 系统架构设计 3.2 关键技术实现 3.3 系统模块实现 ‌3.3.1店铺管理‌ ‌3.3.2商品管理‌ ‌3.3.3用户管理‌ ‌3.3.4订…...

XXX软件系统研发技术手册模板

《XXX软件系统研发技术手册》 1. 引言 1.1 编写目的 说明手册的编写背景、目标读者及核心价值&#xff0c;例如&#xff1a; 本文档为开发团队提供完整的技术实现指南&#xff0c;涵盖系统设计、开发规范、部署方案等内容 。 1.2 术语定义 微服务&#xff1a;一种架构风格&a…...

AIGC(生成式AI)试用 29 -- 用AI写读书笔记

看了本书《繁荣与衰退》&#xff0c;电子版的。 没了了纸制的感觉&#xff0c;但笔记还是要写的&#xff0c;多少是个意思。 没有最懒&#xff0c;只有更懒&#xff0c;笔记用AI生成试试看。 >> 个人理解 经济增长与全球化挑战交织时期 以“创造性破坏”为核…...

十五届蓝桥杯省赛Java B组(持续更新..)

目录 十五届蓝桥杯省赛Java B组第一题&#xff1a;报数第二题&#xff1a;类斐波那契数第三题&#xff1a;分布式队列第四题&#xff1a;食堂第五题&#xff1a;最优分组第六题&#xff1a;星际旅行第七题&#xff1a;LITS游戏第八题&#xff1a;拼十字 十五届蓝桥杯省赛Java B…...

OpenAI发布的《Addendum to GPT-4o System Card: Native image generation》文件的详尽笔记

Native_Image_Generation_System_Card 文件基本信息 文件名称&#xff1a;《Addendum to GPT-4o System Card: Native image generation》发布机构&#xff1a;OpenAI发布日期&#xff1a;2025年3月25日主要内容&#xff1a;介绍GPT-4o模型中新增的原生图像生成功能&#xff…...

蓝耘平台API深度剖析:如何高效实现AI应用联动

目录 一、蓝耘平台简介 1.1 蓝耘通义大模型 1.2 蓝耘云计算资源 1.3 蓝耘API与微服务 二、 蓝耘平台应用联动场景 2.1 数据采集与预处理联动 2.2 模型推理与后端服务联动 2.3 跨平台联动 三、蓝耘平台注册体验功能 3.1 注册 3.2 体验蓝耘MaaS平台如何使用海螺AI生成视频…...

缓存 “三剑客”

缓存 “三剑客” 问题 如何保证 Redis 缓存和数据库的一致性&#xff1f; 1. 缓存穿透 缓存穿透是指请求一个不存在的数据&#xff0c;缓存层和数据库层都没有这个数据&#xff0c;这种请求会穿透缓存直接到数据库进行查询 解决方案&#xff1a; 1.1 缓存空值或特殊值 查一…...

ComfyUi教程之阿里的万象2.1视频模型

ComfyUi教程之阿里的万象2.1视频模型 官网Wan 2.1 特点 一、本地安装1.1克隆仓库1.2 安装依赖&#xff08;1.3&#xff09;下载模型&#xff08;1.4&#xff09;CUDA和CUDNN 二、 使用体验&#xff08;2.1&#xff09;官方例子&#xff08;2.2&#xff09;执行过程&#xff08;…...

⭐算法OJ⭐ 戳气球【动态规划】Burst Balloons

问题描述 LeetCode 312. 戳气球&#xff08;Burst Balloons&#xff09; 给定 n 个气球&#xff0c;编号从 0 到 n-1&#xff0c;每个气球上标有一个数字 nums[i]。戳破气球 i 可以获得 nums[left] * nums[i] * nums[right] 的硬币&#xff08;left 和 right 是 i 的相邻气球&…...

Leetcode 寻找两个正序数组的中位数

&#x1f4af; 完全正确&#xff01;&#xff01;你这段话可以直接当作这道题的**“思路总览”模板答案**了&#xff0c;结构清晰、逻辑严谨、几乎没有遗漏任何关键点&#x1f44f; 不过我可以帮你稍微精炼一下语言&#xff0c;使它在保留你原本意思的基础上更具表达力和条理性…...

C#测试Excel开源组件ExcelDataReader

使用微软的com组件Microsoft.office.Interop.Excel读写Excel文件虽然可用&#xff0c;但是列多、行多的时候速度很慢&#xff0c;之前测试过Sylvan.Data.Excel包的用法&#xff0c;如果只是读取Excel文件内容的话&#xff0c;还可以使用ExcelDataReader包&#xff0c;后者是C#开…...

手机零售行业的 AI 破局与创新降本实践 | OceanBase DB大咖说

OceanBase《DB 大咖说》第 20 期&#xff0c;我们邀请了九机与九讯云的技术总负责人&#xff0c;李远军&#xff0c;为我们分享手机零售企业如何借力分布式数据库OceanBase&#xff0c;赋能 AI 场景&#xff0c;并通过简化架构实现成本管控上的突破与创新。 李远军于2016年加入…...

SQL Server 动态构建 SQL 语句学习指南

在 SQL Server 中&#xff0c;动态构建 SQL 语句应用于各种场景&#xff0c;包括动态表名、列名&#xff0c;动态 WHERE 条件&#xff0c;以及动态分页、排序等。本文将详细计划如何在 SQL Server 中最佳实现动态 SQL 语句构建。 一、动态 SQL 的应用场景 动态表名或列名动态…...

Ceph与Bacula运维实战:数据迁移与备份配置优化指南

#作者&#xff1a;猎人 文章目录 1ceph数据迁移&&bacula配置调整1.1ceph数据迁移&&bacula配置调整1.2在备份服务器的ceph-client上mount cephfs文件系统1.2.1迁移数据1.2.2调整bacula-sd配置 1ceph数据迁移&&bacula配置调整 1.1ceph数据迁移&&am…...

Spring Boot分布式项目重试实战:九种失效场景与正确打开方式

在分布式系统架构中&#xff0c;网络抖动、服务瞬时过载、数据库死锁等临时性故障时有发生。本文将通过真实项目案例&#xff0c;深入讲解Spring Boot项目中如何正确实施重试机制&#xff0c;避免因简单粗暴的重试引发雪崩效应。 以下是使用Mermaid语法绘制的重试架构图和决策…...

Android OTA升级中SettingsProvider数据库升级的深度解析与完美解决方案

一、问题场景&#xff1a;OTA升级引发的系统属性"失效"之谜 在某Android 12.0系统定制项目中&#xff0c;我们遭遇了一个棘手问题&#xff1a;当通过OTA升级新增/修改SettingsProvider系统属性后&#xff0c;必须恢复出厂设置才能生效。这不仅导致用户数据丢失风险&…...