借助libcurl实现C++客户端请求
最近有个需求是C++作为客户端请求服务器,获取返回结果,查找了一些库C++网络库,其中mongoose只有一个.h头文件和一个.c源文件,比较方便且轻量化,客户端上传文件可以跑通,但是上传json数据时需要自己编写报文头,自己不太懂网络这一块,所以最终采用了curl库。
一、libcurl库编译安装
curl功能比较完善,可以根据自身功能需求进行编译,我这里只需要作为客户端请求服务端,所以编译的时候去掉了很多东西,这样作为第三方库依赖也会相应减少。
1.1 linux编译
如果直接git拉取的代码,需要先运行buildconf
生成./configure
文件
- step1
$ ./configure --prefix=/root/package/curl_build --disable-shared --disable-thread --without-ssl --disable-ldap --disable-ldaps --without-zlib
如果产生以下错误
configure: error: cannot find install-sh
则需要安装以下内容
sudo apt-get install automake autoconf libtool
然后执行autoreconf -vif
,执行完后再参照step1进行
- step2
$ make
- step3
$ make install
在/root/package/curl_build目录下的bin文件中,运行./curl --version
查看编译后的库支持的功能,
运行./curl-config --static-libs
或者ldd curl
查看依赖的库文件
1.2 windows编译
参照winbuild
目录下的README.md文件,如果直接从git拉取的源码,首先需要运行buildconf.bat
,生成\src\tool_hugehelp.c以及Makefile文件
否则会报以下错误
error:
Nmake: fatal error u1073: Don't know how to make ".. src\tool_ hugehelp.c”
NMAKE : fatal error U1077: ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\HostX86\x86\nmake.exe"": fatal error "0x2" Stop.
- step1
$ cd curl-7.70.0/winbuild
- step2
select vs2019x64 Native Tools Command Prompt for vs 2019
with manager(管理员身份打开)
nmake /f Makefile.vc mode=static VC=15 MACHINE=x64 DEBUG=no ENABLE_WINSSL=no ENABLE_IDN=no ENABLE_SSPI=no
- step3
返回curl根目录,找到builds目录,
选择libcurl-vc15-x64-release-static-ipv6
,点击可以看到bin
,include
以及lib
三个文件
在bin目录下,运行./curl.exe --version
查看编译后的库支持的功能,
利用Dependency Walker
工具可查看依赖的库文件
二、使用文档
https://curl.se/docs/install.html
https://curl.se/libcurl/c/libcurl.html
https://catonmat.net/cookbooks/curl
三、代码实现
详细代码见github
常见问题
我这里编译的是静态库,集成在工程中编译时会出现undefined reference
的错误
解决方式
在curl.h文件开头添加
#ifdef _WIN32
#define NOMINMAX
#define CURL_STATICLIB
#endif
或者在调用时用extern C
extern "C"
{
#include "curl.h"
}
点击展开mongoose部分代码
// Copyright (c) 2021 Cesanta Software Limited
// All rights reserved
//
// Example HTTP client. Connect to `s_url`, send request, wait for a response,
// print the response and exit.
// You can change `s_url` from the command line by executing: ./example YOUR_URL
//
// To enable SSL/TLS for this client, build it like this:
// make MBEDTLS=/path/to/your/mbedtls/installation
// make OPENSSL=/path/to/your/openssl/installation
//#include <string>
//#include <stdio.h>
#include "mongoose.h"
#include "mjson.h"
// The very first web page in history. You can replace it from command line
//static const char* s_url = "http://localhost:8080/world"; // Send GET request
static const char* s_url = "http://192.168.102.116:8000/mesh/recognize"; // Send Json data
// Print HTTP response and signal that we're done
static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
if (ev == MG_EV_CONNECT) {
// Connected to server. Extract host name from URL
struct mg_str host = mg_url_host(s_url);
// Send GET request
/*mg_printf(c,
"GET %s HTTP/1.0\r\n"
"Host: %.*s\r\n"
"\r\n",
mg_url_uri(s_url), (int)host.len, host.ptr);*/
// Send Json data
char* str = NULL;
mjson_printf(mjson_print_dynamic_buf, &str, "{%Q:%Q, %Q:%Q}", "file_path",
"E:/code/python_web/MeshCNN/test_models/test.obj",
"filename", "test.obj");
mg_printf(c,
"POST %s HTTP/1.0\r\n"
"Host: %.*s\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Content-Length: %lu\r\n"
"\r\n"
"%s",
mg_url_uri(s_url), (int)host.len, host.ptr, (unsigned long)strlen(str), str);
free(str);
// If you want to upload a file, create a form upload request like this:
const char* model_path = "E:/code/python_web/MeshCNN/test_models/test.obj";
const char* model_name = "test.obj";
size_t file_size = mg_file_size(model_path);
char *file_data = mg_file_read(model_path);
const char* boundary = "----BoundaryNetworkf912decMA4YWxkTrZu0gW";
char tmp[256];
snprintf(tmp, sizeof(tmp),
"%s\r\n"
"Content-Disposition: form-data; name=file; filename=%s\r\n"
"Content-Type: application/octet-stream\r\n"
"\r\n",
boundary, model_name);
printf("file_size: %u\n", file_size);
mg_printf(c,
"POST %s?name=%s&offset=%d HTTP/1.1\r\n"
"Host: %.*s\r\n"
"Content-Length: %lu\r\n"
"Content-Type: multipart/form-data; boundary=%s\r\n"
"Accept: */*\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"\r\n",
mg_url_uri(s_url), model_name, file_size, (int)host.len, host.ptr,
(unsigned long)(file_size + strlen(tmp) + strlen(boundary) + 2),
boundary);
mg_printf(c, "%s", tmp);
mg_send(c, file_data, file_size);
mg_printf(c, "%s\r\n", boundary);
free(file_data);
}
else if (ev == MG_EV_HTTP_MSG) {
// Response is received. Print it
struct mg_http_message* hm = (struct mg_http_message*)ev_data;
printf("********** start **********\n");
printf("%s\n", hm->body.ptr);
printf("********** end **********\n");
c->is_closing = 1; // Tell mongoose to close this connection
*(bool*)fn_data = true; // Tell event loop to stop
}
else if (ev == MG_EV_ERROR) {
*(bool*)fn_data = true; // Error, tell event loop to stop
}
}
int main(int argc, char* argv[]) {
struct mg_mgr mgr; // Event manager
bool done = false; // Event handler flips it to true
if (argc > 1) s_url = argv[1]; // Use URL from command line
mg_log_set("3"); // Set to 0 to disable debug
mg_mgr_init(&mgr); // Initialise event manager
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
mg_mgr_free(&mgr); // Free resources
return 0;
}
参考资料
https://curl.se/docs/install.html
https://blog.csdn.net/px41834/article/details/81627170
https://blog.csdn.net/cym1990/article/details/79851039
https://my.oschina.net/u/4324616/blog/4326368
https://www.jianshu.com/p/eef34d40f51c
https://blog.csdn.net/u014664846/article/details/91411997
https://blog.csdn.net/sinat_29891353/article/details/72526173
https://blog.csdn.net/qq_41482046/article/details/93379733
https://blog.csdn.net/giveaname/article/details/107388468
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端