HTTP 作为互联网通信的核心协议,是 C/C++ 后端开发中构建网络服务的基础能力。本文将从 HTTP 核心请求方法入手,详解 C/C++ 实现 HTTP 服务的主流方式,结合实战代码示例,帮助开发者快速掌握从基础到进阶的实现思路。

一、HTTP的用途
不管是现在大火的大模型接口调用、Token 计算传输,还是咱们做网站时的前后端交互、拿数据、传数据,底层跑的全都是 HTTP 请求。无论是大模型通过 API 完成文本生成、Token 流式返回,还是前端请求后端接口获取数据、提交表单,亦或是网页加载图片、样式、脚本等静态资源,本质上都是遵循 HTTP/HTTPS 的请求 - 响应模式。它以简洁、标准化的通信方式,成为互联网应用的通用语言,覆盖了从大模型服务到 Web 开发的绝大多数场景,支撑起了各类线上功能的稳定运行与数据交互。
二、HTTP 核心请求方法
在 C/C++ HTTP 服务开发中,无需实现所有 HTTP 方法,只需聚焦业务高频使用的核心方法,以下是服务端必须支持的 6 种核心方法及处理逻辑:
| HTTP 方法 | 核心用途 |
|---|---|
| GET | 获取资源(如查询数据) |
| POST | 提交数据(如创建资源) |
| PUT | 全量更新资源 |
| PATCH | 部分更新资源 |
| DELETE | 删除资源 |
| OPTIONS | 跨域预检 |
三、HTTP 接收的数据格式(Content-Type)
| 数据格式 | 用途介绍 |
|---|---|
| application/json | 传 JSON 对象,现在接口最主流 |
| application/x-www-form-urlencoded | 普通表单格式:key1=val1&key2=val2,浏览器原生表单默认格式 |
| multipart/form-data | 全上传文件专用,可同时传文本 + 文件 |
| text/plain | 纯文本 |
| application/octet-stream | 二进制流(下载文件、传字节流用) |
四、HTTP数据交互过程
┌─────────────────┐
│ 客户端 │ (浏览器/前端/大模型调用端)
│ - 发起HTTP请求 │
└────────┬────────┘
│
▼
┌─────────────────────────────────────┐
│ HTTP请求报文 │
│ 请求行:GET/POST + 接口地址 + 协议 │
│ 请求头:Content-Type/Cookie等 │
│ 请求体:提交的参数/文件/Token等 │
└────────┬─────────────────────────────┘
│
▼
┌─────────────────┐
│ HTTP服务端 │ (后端服务器)
│ 解析请求 │
│ 处理业务逻辑 │
│ 生成响应数据 │
└────────┬────────┘
│
▼
┌─────────────────────────────────────┐
│ HTTP响应报文 │
│ 状态行:200成功/404失败/500错误 │
│ 响应头:Access-Control-Allow-Origin │
│ 响应体:JSON/HTML/图片/文本等数据 │
└────────┬─────────────────────────────┘
│
▼
┌─────────────────┐
│ 客户端 │
│ 解析响应数据 │
│ 渲染展示/更新 │
└─────────────────┘
五、基于Mongoose的封装
Mongoose 是一个面向 C/C++ 的网络库。它提供事件驱动的非阻塞 支持TCP、UDP、HTTP、WebSocket、MQTT及其他协议的API。它是设计好的 用于连接设备并使其上线。自2004年起上市,使用过 通过大量开源和商业产品------它甚至运行在 国际空间站!
代码位置:Mongoose Github
至于这里为什么使用mongoose,因为使用方便,不需要编译库,只需要将mongoose.h和mongoose.c放到项目中就可直接使用。
1 Mongoose服务端代码
下面是基于Mongoose封装的一个HTTP服务器:
c++
////MGSrvUtil.hpp
#include "mongoose.h"
#include <thread>
#include <string>
#include <vector>
class MGSrvUtil
{
public:
MGSrvUtil()
{
m_sConnection = nullptr;
memset(&m_mgMessage, 0, sizeof(m_mgMessage));
m_nMGDebugLevel = MG_LL_INFO;
m_bActivate = false;
}
~MGSrvUtil()
{
}
public:
/////enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
void InitParameter(const char* saveFilePath,int debugLevel);
/////example:"http://0.0.0.0:8000";
void StartMGHttpSrv(const char* http_addr);
void StopHttpSrv()
{
m_bActivate = false;
}
private:
//MG Function
static void mg_callback_recv(struct mg_connection* c, int ev, void* ev_data);
void HandleCallbackRecv(struct mg_connection* c, int ev, void* ev_data);
void ThreadStartSrv(const char* http_addr);
void HandleHttpRequest(struct mg_connection* c, struct mg_http_message* hm);
////////////HTTP Method Handle
void HandleGetRequest(struct mg_connection* c, struct mg_http_message* hm);
void HandlePostRequest(struct mg_connection* c, struct mg_http_message* hm);
void HandlePutRequest(struct mg_connection* c, struct mg_http_message* hm);
void HandlePatchRequest(struct mg_connection* c, struct mg_http_message* hm);
void HandleDeleteRequest(struct mg_connection* c, struct mg_http_message* hm);
void HandleOptionsRequest(struct mg_connection* c, struct mg_http_message* hm);
private:
//MG Srv Parameters
struct mg_mgr m_mgMessage;
struct mg_connection* m_sConnection;
const char* m_fileSaveDir = NULL;
int m_nMGDebugLevel;
bool m_bActivate;
};
void MGSrvUtil::InitParameter(const char* saveFilePath, int debugLevel = MG_LL_INFO)
{
m_fileSaveDir = saveFilePath;
m_nMGDebugLevel = debugLevel;
}
void MGSrvUtil::ThreadStartSrv(const char* http_addr)
{
mg_log_set(m_nMGDebugLevel);
mg_mgr_init(&m_mgMessage);
if ((m_sConnection = mg_http_listen(&m_mgMessage, http_addr, mg_callback_recv, this)) == NULL)
{
MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
http_addr));
exit(EXIT_FAILURE);
}
// Start infinite event loop
MG_INFO(("Mongoose version : v%s", MG_VERSION));
MG_INFO(("Listening on : %s", http_addr));
MG_INFO(("Upload dir : %s", m_fileSaveDir ? m_fileSaveDir : "(unset)"));
while (true)
{
mg_mgr_poll(&m_mgMessage, 1000);
if (!m_bActivate)
{
mg_mgr_free(&m_mgMessage);
break;
}
}
}
void MGSrvUtil::StartMGHttpSrv(const char* http_addr)
{
m_bActivate = true;
std::thread start(&MGSrvUtil::ThreadStartSrv, this, http_addr);
start.detach();
}
void MGSrvUtil::mg_callback_recv(struct mg_connection* c, int ev, void* ev_data)
{
MGSrvUtil* instance = (MGSrvUtil*)c->fn_data;
instance->HandleCallbackRecv(c, ev, ev_data);
}
void MGSrvUtil::HandleCallbackRecv(struct mg_connection* c, int ev, void* ev_data)
{
switch (ev)
{
case MG_EV_HTTP_MSG:
{
struct mg_http_message* hm = static_cast<struct mg_http_message*>(ev_data);
HandleHttpRequest(c, hm);
break;
}
case MG_EV_CLOSE:
{
MG_DEBUG(("Connection closed"));
break;
}
case MG_EV_ERROR:
{
MG_ERROR(("Connection error: %s", (char*)ev_data));
break;
}
default:
break;
}
}
void MGSrvUtil::HandleHttpRequest(struct mg_connection* c, struct mg_http_message* hm)
{
std::string method(hm->method.buf, hm->method.len);
if (method == "GET")
{
HandleGetRequest(c, hm);
}
else if (method == "POST")
{
std::cout << "Post Request Recv!!" << std::endl;
HandlePostRequest(c, hm);
}
else if (method == "PUT")
{
HandlePutRequest(c, hm);
}
else if (method == "PATCH")
{
HandlePatchRequest(c, hm);
}
else if (method == "DELETE")
{
HandleDeleteRequest(c, hm);
}
else if (method == "OPTIONS")
{
HandleOptionsRequest(c, hm);
}
else
{
mg_http_reply(c, 405, "Content-Type: text/plain\r\n", "%s", "Method Not Allowed");
}
MG_INFO(("%.*s %.*s %lu -> %.*s %lu",
hm->method.len, hm->method.buf,
hm->uri.len, hm->uri.buf,
hm->body.len,
3, c->send.buf + 9, c->send.len));
}
// ------------------------------ HTTP Method Handle ------------------------------
void MGSrvUtil::HandleGetRequest(struct mg_connection* c, struct mg_http_message* hm)
{
mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}
void MGSrvUtil::HandlePostRequest(struct mg_connection* c, struct mg_http_message* hm)
{
std::string full_uri(hm->uri.buf, hm->uri.len);
std::cout << "Full URI: " << full_uri << std::endl;
if ((mg_match(hm->uri, mg_str("/test"), NULL)))
{
std::cout << "test" << std::endl;
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "/test success");
// Log request
//MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.buf,
// hm->uri.len, hm->uri.buf, hm->body.len, 3, c->send.buf + 9,
// c->send.len));
}
else if((mg_match(hm->uri, mg_str("/upload"), NULL)))
{
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "/upload success");
//std::string base64_data(hm->body.buf, hm->body.len);
std::cout << "upload" << std::endl;
}
else
{
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", "success");
std::cout << "Not Found Method" << std::endl;
}
}
void MGSrvUtil::HandlePutRequest(struct mg_connection* c, struct mg_http_message* hm)
{
mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}
void MGSrvUtil::HandlePatchRequest(struct mg_connection* c, struct mg_http_message* hm)
{
mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}
void MGSrvUtil::HandleDeleteRequest(struct mg_connection* c, struct mg_http_message* hm)
{
mg_http_reply(c, 501, "Content-Type: text/plain\r\n", "Not Implemented");
}
void MGSrvUtil::HandleOptionsRequest(struct mg_connection* c, struct mg_http_message* hm)
{
mg_http_reply(c, 200,
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n",
"");
}
2 Mongoose客户端代码
//MGCltUtil.hpp
#pragma once
#include "mongoose.h"
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <atomic>
class MGCltUtil
{
public:
MGCltUtil()
{
mg_mgr_init(&m_mgr);
m_done = false;
m_bTimeOut = false;
m_timeout_ms = 1500;
m_response_data = "";
m_response_code = 0;
m_url = "";
}
~MGCltUtil()
{
mg_mgr_free(&m_mgr);
}
public:
static void callback_client_recv(struct mg_connection* c, int ev, void* ev_data);
void HandleClientRecv(struct mg_connection* c, int ev, void* ev_data);
// 发送HTTP请求,支持自定义method、content_type、body
// method: "GET", "POST", "PUT", "DELETE" 等
// content_type: "application/json", "text/plain", "application/x-www-form-urlencoded" 等
// body: 请求体内容,GET请求可传空字符串
bool SendRequest(const std::string& url, const std::string& method = "GET",
const std::string& content_type = "application/json",
const std::string& body = "", uint64_t timeout_ms = 1500);
// new add,upload image
bool UploadJpegFile(const std::string& url,
const std::string& file_path,
const std::vector<uint8_t>& jpeg_data,
uint64_t timeout_ms = 30000);
// 获取响应数据
std::string GetResponseData() const { return m_response_data; }
// 获取响应状态码
int GetResponseCode() { return m_response_code; }
private:
struct mg_mgr m_mgr;
bool m_done;
bool m_bTimeOut;
uint64_t m_timeout_ms;
std::string m_response_data;
int m_response_code;
std::string m_url;
std::string m_method;
std::string m_content_type;
std::string m_body;
///upload image parameters
std::vector<uint8_t> m_upload_data;
std::string m_file_name;
};
bool MGCltUtil::SendRequest(const std::string& url, const std::string& method,
const std::string& content_type, const std::string& body, uint64_t timeout_ms)
{
m_done = false;
m_bTimeOut = false;
m_url = url;
m_method = method;
m_content_type = content_type;
m_body = body;
m_timeout_ms = timeout_ms;
m_response_data = "";
m_response_code = 0;
if (m_url.find("http://") != 0 && m_url.find("https://") != 0)
{
std::cout << "Invalid URL format, should start with http:// or https://" << std::endl;
return false;
}
mg_http_connect(&m_mgr, m_url.c_str(), callback_client_recv, this);
while (!m_done)
{
mg_mgr_poll(&m_mgr, 50);
if (m_bTimeOut)
{
std::cout << "Connect Timeout!!!" << std::endl;
return false;
}
}
return true;
}
// multipart/form-data JPEG File Upload
bool MGCltUtil::UploadJpegFile(const std::string& url,
const std::string& file_path,
const std::vector<uint8_t>& jpeg_data,
uint64_t timeout_ms)
{
m_done = false;
m_bTimeOut = false;
m_url = url;
m_timeout_ms = timeout_ms;
m_response_data = "";
m_response_code = 0;
m_upload_data = jpeg_data;
size_t pos = file_path.find_last_of("/\\");
m_file_name = (pos == std::string::npos) ? file_path : file_path.substr(pos + 1);
if (m_url.find("http://") != 0) return false;
if (jpeg_data.empty()) return false;
mg_http_connect(&m_mgr, m_url.c_str(), callback_client_recv, this);
while (!m_done)
{
mg_mgr_poll(&m_mgr, 50);
if (m_bTimeOut) { std::cout << "上传超时" << std::endl; return false; }
}
return (m_response_code == 200);
}
void MGCltUtil::callback_client_recv(struct mg_connection* c, int ev, void* ev_data)
{
MGCltUtil* instance = static_cast<MGCltUtil*>(c->fn_data);
if (instance != nullptr)
{
instance->HandleClientRecv(c, ev, ev_data);
}
}
void MGCltUtil::HandleClientRecv(struct mg_connection* c, int ev, void* ev_data)
{
switch (ev)
{
case MG_EV_OPEN:
*(uint64_t*)c->data = mg_millis() + m_timeout_ms;
break;
case MG_EV_POLL:
if (mg_millis() > *(uint64_t*)c->data && (c->is_connecting || c->is_resolving))
{
m_bTimeOut = true;
mg_error(c, "Connect timeout");
}
break;
case MG_EV_CONNECT:
{
struct mg_str host = mg_url_host(m_url.c_str());
int content_length = (int)m_body.size();
// 发送请求行和Host
mg_printf(c,
"%s %s HTTP/1.1\r\n"
"Host: %.*s\r\n"
"Content-Type: %.*s\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n",
m_method.c_str(), mg_url_uri(m_url.c_str()),
(int)host.len, host.buf,
(int)m_content_type.size(), m_content_type.c_str(),
content_length);
mg_printf(c, "%s", "\r\n"); // 结束头部
// 发送body
if (content_length > 0)
{
mg_send(c, m_body.c_str(), content_length);
}
}
break;
case MG_EV_HTTP_MSG:
{
struct mg_http_message* hm = (struct mg_http_message*)ev_data;
m_response_code = mg_http_status(hm);
m_response_data = std::string(hm->body.buf, hm->body.len);
std::cout << "Response Status: " << m_response_code << std::endl;
std::cout << "Response Body: " << m_response_data << std::endl;
c->is_draining = 1;
m_done = true;
}
break;
case MG_EV_ERROR:
m_done = true;
break;
}
}
int main(int argc, char* argv[])
{
MGCltUtil client;
// GET Method
client.SendRequest("http://127.0.0.1:1234/test");
// // POST JSON
client.SendRequest("http://127.0.0.1:1234//cmd_move", "POST", "application/json", R"({"key":"value"})");
// // POST Method
// client.SendRequest("http://127.0.0.1:1234/test", "POST", "application/x-www-form-urlencoded", "name=hello&age=18");
// // PUT Method
// client.SendRequest("http://127.0.0.1:1234/api/data", "PUT", "text/plain", "updated content");
getchar();
return 0;
}
3 libcurl客户端代码
c++
#include <curl/curl.h>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <atomic>
#include <chrono>
class CurlCltUtil
{
public:
CurlCltUtil()
{
m_done = false;
m_bTimeOut = false;
m_timeout_ms = 1500;
m_response_data = "";
m_response_code = 0;
m_url = "";
m_response_headers = ""; // 新增
// libcurl 全局初始化(一次即可)
curl_global_init(CURL_GLOBAL_ALL);
}
~CurlCltUtil()
{
curl_global_cleanup();
}
public:
// 发送HTTP请求,支持自定义method、content_type、body
bool SendRequest(const std::string& url, const std::string& method = "GET",
const std::string& content_type = "application/json",
const std::string& body = "", uint64_t timeout_ms = 1500);
// 上传JPEG文件(multipart/form-data)
bool UploadJpegFile(const std::string& url,
const std::string& file_path,
const std::vector<uint8_t>& jpeg_data,
uint64_t timeout_ms = 30000);
std::string GetResponseData() const { return m_response_data; }
int GetResponseCode() { return m_response_code; }
std::string GetResponseHeaders() const { return m_response_headers; }
void PrintResponse() {
std::cout << "\n===== HTTP RESPONSE =====\n";
std::cout << "Status Code: " << m_response_code << "\n\n";
std::cout << "Headers:\n" << m_response_headers << "\n";
std::cout << "Body:\n" << m_response_data << "\n";
std::cout << "=========================\n\n";
}
private:
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s);
static size_t HeaderCallback(void* contents, size_t size, size_t nmemb, std::string* s); // 新增
private:
bool m_done;
bool m_bTimeOut;
uint64_t m_timeout_ms;
std::string m_response_data;
std::string m_response_headers; // 新增
int m_response_code;
std::string m_url;
std::string m_method;
std::string m_content_type;
std::string m_body;
// 上传图片用
std::vector<uint8_t> m_upload_data;
std::string m_file_name;
};
// ====================== 实现 ======================
size_t CurlCltUtil::WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s)
{
size_t newLength = size * nmemb;
try {
s->append((char*)contents, newLength);
}
catch (std::bad_alloc& e) {
return 0;
}
return newLength;
}
// 新增:接收响应头
size_t CurlCltUtil::HeaderCallback(void* contents, size_t size, size_t nmemb, std::string* s)
{
size_t newLength = size * nmemb;
try {
s->append((char*)contents, newLength);
}
catch (std::bad_alloc& e) {
return 0;
}
return newLength;
}
bool CurlCltUtil::SendRequest(const std::string& url, const std::string& method,
const std::string& content_type, const std::string& body, uint64_t timeout_ms)
{
m_done = false;
m_bTimeOut = false;
m_url = url;
m_method = method;
m_content_type = content_type;
m_body = body;
m_timeout_ms = timeout_ms;
m_response_data.clear();
m_response_headers.clear(); // 新增
m_response_code = 0;
CURL* curl = curl_easy_init();
if (!curl) return false;
// 设置URL
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
// 设置请求方法
if (m_method == "POST")
curl_easy_setopt(curl, CURLOPT_POST, 1L);
else if (m_method == "PUT")
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
else if (m_method == "DELETE")
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
else
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
// 超时
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)timeout_ms);
// 响应数据接收
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &m_response_data);
// 新增:接收响应头
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &m_response_headers);
// POST/PUT 数据
struct curl_slist* headers = NULL;
if (!m_content_type.empty()) {
std::string h = "Content-Type: " + m_content_type;
headers = curl_slist_append(headers, h.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}
if ((m_method == "POST" || m_method == "PUT") && !m_body.empty()) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, m_body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)m_body.size());
}
// 执行请求
CURLcode res = curl_easy_perform(curl);
// 获取状态码
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &m_response_code);
// 清理
if (headers) curl_slist_free_all(headers);
curl_easy_cleanup(curl);
m_done = true;
if (res != CURLE_OK) {
if (res == CURLE_OPERATION_TIMEDOUT)
m_bTimeOut = true;
return false;
}
return true;
}
// 上传 JPEG(multipart/form-data)
bool CurlCltUtil::UploadJpegFile(const std::string& url,
const std::string& file_path,
const std::vector<uint8_t>& jpeg_data,
uint64_t timeout_ms)
{
m_done = false;
m_bTimeOut = false;
m_url = url;
m_timeout_ms = timeout_ms;
m_response_data.clear();
m_response_headers.clear(); // 新增
m_response_code = 0;
m_upload_data = jpeg_data;
size_t pos = file_path.find_last_of("/\\");
m_file_name = (pos == std::string::npos) ? file_path : file_path.substr(pos + 1);
if (m_url.empty() || jpeg_data.empty()) return false;
CURL* curl = curl_easy_init();
if (!curl) return false;
curl_mime* mime = curl_mime_init(curl);
curl_mimepart* part = curl_mime_addpart(mime);
curl_mime_name(part, "file");
curl_mime_filename(part, m_file_name.c_str());
curl_mime_type(part, "image/jpeg");
curl_mime_data(part, (const char*)jpeg_data.data(), jpeg_data.size());
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)timeout_ms);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &m_response_data);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback); // 新增
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &m_response_headers); // 新增
CURLcode res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &m_response_code);
curl_mime_free(mime);
curl_easy_cleanup(curl);
m_done = true;
if (res != CURLE_OK) {
if (res == CURLE_OPERATION_TIMEDOUT) m_bTimeOut = true;
return false;
}
return (m_response_code == 200);
}
// ====================== 测试 main ======================
int main(int argc, char* argv[])
{
CurlCltUtil client;
// GET
bool ret = client.SendRequest("http://192.168.0.128:1234/test");
if (ret) {
client.PrintResponse(); // 直接打印 code + header + body
}
// POST JSON
//client.SendRequest("http://192.168.1.2:1234/cmd_move", "POST", "application/json", R"({"key":"value"})");
//client.PrintResponse();
getchar();
return 0;
}
六、基于libhv的封装
基于libhv的封装本来是想写一块的,但是考虑到需要编译,安装,篇幅太长于是新开了一篇文章:
libhv 安装与使用全流程教程
七、上述代码库对比
| 项目 | curl/libcurl | libhv | mongoose |
|---|---|---|---|
| 核心定位 | 命令行工具 + 客户端传输库 | 全功能高性能网络框架(客户端 + 服务端) | 极简嵌入式网络库(客户端 + 服务端) |
| 设计目标 | 支持最多协议、最稳定的跨平台传输 | 高性能、易用、全栈网络开发 | 极小体积、零依赖、嵌入式友好 |
| 开源协议 | curl 许可证(类似 MIT,宽松) | BSD 3-Clause | GPLv2 / 商业双授权 |
| 是否可商用 | 完全可商用,无版权污染 |
完全可商用,无版权污染 |
GPL 版不可闭源商用;需买商业授权 |
总结
HTTP是C/C++后端开发、互联网通信的核心协议,贯穿前后端交互、大模型接口调用等各类场景,掌握HTTP请求方法、数据格式和通信流程,是搭建网络服务的基础。本文梳理了高频HTTP请求方法与常用数据格式,拆解了完整的HTTP交互流程,还提供了Mongoose服务端、客户端以及libcurl客户端的实战封装代码,上手即用、适配工程开发。同时对比了curl/libcurl、libhv、Mongoose三大库的差异,开发者可按需选择:Mongoose轻量零依赖,适合嵌入式场景;libhv高性能全能,适合高并发服务;libcurl协议齐全、稳定易用,专攻客户端传输,助力开发者高效搭建HTTP服务。