news 2026/9/8 7:37:55

VS2013调用libcurl示例工程:配置、编译与HTTP请求实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VS2013调用libcurl示例工程:配置、编译与HTTP请求实战

简介:这是一份基于Visual Studio 2013的C++示例工程,面向需要在Windows下快速上手libcurl的开发者,演示如何集成libcurl完成HTTP/HTTPS及FTP等网络通信。工程内包含完整源码与工程配置,通过curl_easy_setopt、回调函数、curl_easy_perform等接口展示GET/POST请求、SSL安全连接、代理与重定向等核心用法,并覆盖初始化、设置URL、执行请求与清理的完整调用流程。压缩包共61个文件,以18个头文件、16个DLL、6个PDB调试文件为主,另含lib、exp、cmake等编译辅助文件,整体体积仅7.03MB,目录按inc/src/x64等模块划分,便于直接对照学习。目前已有579人学习下载。借助该工程可省去自行搭建libcurl环境的繁琐流程,通过阅读和运行示例,可直观理解libcurl的回调机制、错误码处理,以及VS2013项目配置中的DLL依赖管理方法,并将其迁移到实际项目中,是一份高效实用的入门参考。

1. 项目背景与目标:为什么要在VS2013里搞libcurl

先说清楚这是个什么东西。libcurl是一个跨平台的网络传输开源库,支持HTTP、HTTPS、FTP、SMTP等一大堆协议,C/C++项目里用它做HTTP请求是最常见的做法之一。而VS2013(Visual Studio 2013)虽然是老物件了,但很多企业级项目、MFC桌面程序、工业控制软件至今还在用,尤其是那些维护多年的老代码库,不是想升级就能升的。

这个“VS2013调用libcurl示例工程”,本质上是解决一个很实际的问题:在老旧的开发环境里,如何把libcurl这个现代网络库用起来,让C++程序可以发HTTP请求、下载文件、调用Web API。核心价值就三个字——“能联网”。一个MFC桌面程序如果需要访问远程服务器、拉取数据、检查更新,libcurl基本是最省事的方案,比你自己封装WinINet或WinHTTP要省太多事。

适合看这篇东西的人,大概分三类。第一类是被老项目绑在VS2013上动弹不得的C++程序员,必须在这个环境下集成新功能。第二类是刚接触libcurl、想把网络功能塞进自己桌面程序里的新手,需要一份能跑通的示例代码。第三类是那种“库都下载好了但就是编译不过”的倒霉蛋,链接错误、找不到头文件、运行库不匹配——这些坑我全踩过,写出来给大家省点时间。

先说一下我的测试环境:Windows 7 x64,VS2013 Update 5,libcurl 7.71.1(源码包),代码写的是控制台工程,方便演示调用流程。MDI框架改动复杂,核心的libcurl调用逻辑是一样的。

2. 环境准备:VS2013安装和libcurl获取,一步都不能省

2.1 VS2013安装的几个关键点

VS2013的安装包现在不太好找,官网下载链接基本已经停了,一般是从MSDN I Tell You这样的镜像站拿。安装的时候有几个坑需要注意。

第一,Win10以上的系统装VS2013,容易卡在“正在安装”界面。这大多不是安装包问题,而是Windows Update服务没开或者.NET Framework版本不兼容。建议安装前先打开控制面板把“.NET Framework 3.5”勾上(包括2.0和3.0子项),然后跑一遍Windows Update,把系统补丁打全,再装VS2013,成功率会高很多。

第二,安装过程必须以管理员身份运行,不然有些组件写不进去。VS2013默认安装路径是C盘,如果C盘空间紧张,可以自定义到别的盘,但要注意后续可能涉及的路径配置问题。

第三,关于激活密钥——网上传的什么“永久激活密钥”基本都是假的,或者早就被封了。VS2013的社区版是免费的,专业版和企业版需要购买许可证。我的建议是:能用社区版就用社区版,功能足够;如果公司有正版授权,那就用公司的账号登录激活。别去折腾那些来路不明的密钥,装系统这种事,越规矩越省心。

提示:VS2013 Update 5一定要装。不装Update 5的话,对C++11的支持很差,后来编译libcurl源码时可能会遇到一些奇怪的语法报错。

2.2 libcurl的获取方式,两种都要讲清楚

libcurl的获取方式主要有两种,我在实际工程中都试过,各有优劣。

方式一:下载预编译的二进制包,从官方curl.se网站下载对应的Windows版本。好处是省事,头文件、库文件都是现成的,解压即用。坏处是版本更新不及时,而且预编译包默认用的是DLL运行库,你工程里如果设置了其他运行时库,可能对不上。

方式二:下载源码(比如7.71.1版本),自己编译。这是最稳妥的方式,因为你完全可以把控编译选项,比如静态链接还是动态链接、是否支持OpenSSL、是否启用特定协议等。我自己的工程就是这么干的,编译出来的libcurl跟我的程序完全匹配,后续部署时不用带着一堆DLL到处跑。

这里要注意,源码编译虽然灵活,但门槛确实高一些。你得先装好依赖库(OpenSSL、zlib等),然后用CMake生成VS2013的工程文件,再编译。一个细节:源码目录里有个winbuild文件夹,里面有nmake的编译脚本,可以用命令行编译,比CMake更简单直接。具体命令是这样:

cd curl-7.71.1/winbuild nmake /f Makefile.vc mode=dll VC=12 ENABLE_WINSSL=yes

VC=12对应的就是VS2013的编译器版本(VC10是2010,VC11是2012,VC12就是2013)。ENABLE_WINSSL=yes表示用Windows自带的SSL库,这样就不用额外编译OpenSSL了。如果你的HTTPS请求涉及自签名证书、双向认证等特殊场景,需要额外配置,但普通场景下ENABLE_WINSSL已经够用。

编译结束后,在curl-7.71.1/build目录下会生成libcurl.dll、libcurl.lib、头文件include目录。把这些文件拷贝出来备用。

3. 工程配置:三个目录一处宏,全弄对就成功了一半

3.1 创建示例工程,选择对的项目类型

打开VS2013,新建项目,选“Win32控制台应用程序”,项目名称随便起,比如“CurlDemo”。在应用程序设置里,把“空项目”勾上。如果你以后要在MFC项目里用,原理完全一样,只是把库文件加到MFC工程里而已,调用代码不用改。

一个真实的经验:很多人图省事,直接用VS2013自带的“Windows服务”或“ATL项目”来跑测试代码,结果编译出来各种链接错误。建议就是老老实实建控制台工程,先把库调通了,再往正式项目里集成。

3.2 配置Include目录、Lib目录和附加依赖项

在解决方案资源管理器里右键项目,选“属性”,然后按照下面这个路径一步步配:

第一步,配置“C/C++” -> “常规” -> “附加包含目录”,把libcurl的include文件夹路径加进去。比如:

E:\third_party\curl-7.71.1\include

这个目录下有curl文件夹,里面是curl.h、easy.h等头文件。代码里#include <curl/curl.h>能编过,靠的就是这个配置。

第二步,配置“链接器” -> “常规” -> “附加库目录”,把lib目录路径加进去:

E:\third_party\curl-7.71.1\build\lib

第三步,配置“链接器” -> “输入” -> “附加依赖项”,填上:

libcurl.lib

注意,如果你链接的是libcurl的dll版本,还需要保证运行时libcurl.dll在你的程序目录或者系统PATH里能找到。如果是静态链接,还需要额外加一些依赖库,这个下面单独说。

3.3 运行时库的选择,一个让人崩溃的坑

这是最容易出问题的地方。VS2013的“项目属性” -> “C/C++” -> “代码生成” -> “运行时库”,有四个选项:多线程调试(/MTd)、多线程(/MT)、多线程调试DLL(/MDd)、多线程DLL(/MD)。

libcurl的预编译版本默认是配合动态运行库(/MD)使用的。如果你在工程里选了静态运行库(/MT),编译时你可能会看到一堆_vsnprintf_beginthread等符号无法解析的错误。

我当时是这么解决的:工程属性里把“配置”切到“Debug”,运行时库选“多线程调试(/MTd)”;配置切到“Release”,运行时库选“多线程(/MT)”。然后从源码编译libcurl的时候,也对应地选静态运行库。

注意静态链接libcurl,因为libcurl会依赖ssl、zlib等库,完整的附加依赖项表大概是:

libcurl.lib ws2_32.lib winmm.lib crypt32.lib wldap32.lib

这些库缺一个,链接器就会报“无法解析的外部符号”。网上有各种说法,有的说还要加normaliz.lib,有的说不用。我的经验是,VS2013 + libcurl 7.71.1 + WinSSL模式,上面五个就够了。如果还报错,再逐个尝试加上。

4. 代码实现:一个完整的HTTP请求要走完这五步

4.1 初始化环境和全局清理

libcurl的使用套路很固定,就像一个“打开-使用-关闭”的过程。第一步是调用curl_global_init()初始化全局环境,这个函数会初始化SSL库、socket库等底层依赖。

#include <iostream> #include <string> #include <curl/curl.h> // 全局初始化只做一次,多次调用也没问题,但建议放在程序入口 curl_global_init(CURL_GLOBAL_DEFAULT); // ... 业务代码 ... // 程序退出时清理 curl_global_cleanup();

CURL_GLOBAL_DEFAULT是默认值,它会把SSL和WinSocket都初始化好。也可以只初始化SSL:CURL_GLOBAL_SSL。但没必要卡那么细,直接用DEFAULT就行。注意,curl_global_initcurl_global_cleanup要成对出现,而且尽量在程序的开头和结尾各调用一次。不要在请求函数里反复调用,会影响性能。

4.2 数据回调函数的写法,很多新手在这里丢数据

libcurl请求返回的数据不是直接给你一个缓冲区,而是通过回调函数一块一块地交给你的。为什么这样设计?因为大文件下载时,数据是一块块到达的,回调机制让你随时处理,避免一次性占用大量内存。

回调函数的签名是固定的:

size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { size_t totalSize = size * nmemb; // userp指向你传入的自定义数据结构,这里用string来存 std::string* str = static_cast<std::string*>(userp); str->append((char*)contents, totalSize); return totalSize; }

关键点有两个。第一,必须返回实际处理的字节数,也就是size * nmemb。如果返回的和接收到的数量不一致,libcurl会认为传输出错。第二,userp参数可以传任意指针,在curl_easy_setopt里通过CURLOPT_WRITEDATA选项传入。这里传一个std::string*过去,数据就自动累积起来了。

经验:回调代码要尽量简洁,不要做耗时操作,比如写磁盘、打日志。因为回调运行在libcurl的内部线程上下文里,拖得越久,传输效率越低。一次下载大文件时,我在回调里直接解析JSON,结果下载速度被拖慢了将近一半。后来改成先把数据存内存,下载完了再统一解析。

4.3 构造请求并执行:easy接口的完整流程

这里演示一个最常见的GET请求,目标URL用https://www.baidu.com,验证HTTPS请求能不能通:

// 创建一个easy句柄 CURL* curl = curl_easy_init(); if (!curl) { std::cerr << "curl_easy_init failed" << std::endl; return -1; } // 设置请求URL curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com"); // 设置跟随重定向 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 设置超时时间(秒) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // 设置SSL证书验证(默认就是开启的,这里显式声明) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); // 设置回调函数和接收数据的容器 std::string response; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // 执行请求 CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform failed: " << curl_easy_strerror(res) << std::endl; } else { long httpCode = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); std::cout << "HTTP Status Code: " << httpCode << std::endl; std::cout << "Response size: " << response.size() << " bytes" << std::endl; std::cout << response << std::endl; // 谨慎输出大响应 } // 清理句柄 curl_easy_cleanup(curl);

代码本身很直白,但我遇到过几个问题,值得多说几句。

第一,超时设置。CURLOPT_CONNECTTIMEOUT是连接超时,CURLOPT_TIMEOUT是总超时。如果你的程序要长时间下载大文件,TIMEOUT设太短会中途断掉;设太长,一旦服务端没有响应,界面就像卡死了一样。另一个实用方案是把CURLOPT_NOSIGNAL设置为1L,防止libcurl在DNS解析时因信号中断导致多线程崩溃。

第二,SSL验证。默认情况下CURLOPT_SSL_VERIFYPEER是开启的,验证服务器证书。但开发阶段如果用的是自签名HTTPS证书,经常验证失败。有两个选择:开发环境可以临时把验证关掉,正式环境必须开启,否则万一中间人攻击,数据就裸奔了。代码里可以加一个宏来控制:

#ifdef _DEBUG curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 调试时跳过证书验证 #else curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem"); // 正式环境指定CA证书 #endif

第三,curl_easy_perform是阻塞式的。如果你的程序有UI界面,MFC里直接调用会导致界面卡住。解法是把请求放到工作线程里,或者用libcurl multi接口做异步。后面会简单提一下,这里先不展开。

4.4 带参数的POST请求,模拟表单提交

实际项目里,GET请求可能只占一半,另一半是POST。POST请求的两种常见方式:URL编码表单(application/x-www-form-urlencoded)和JSON体(application/json)。

表单提交:

// 构造提交数据 std::string postData = "username=admin&password=123456"; // 重新复用上面的curl句柄 curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.100:8080/api/login"); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postData.size());

JSON提交:

std::string jsonData = R"({"name":"libcurl","type":"http"})"; curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.100:8080/api/upload"); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, jsonData.size()); // 设置Content-Type头 struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "Accept: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 执行完后释放头列表 CURLcode res = curl_easy_perform(curl); curl_slist_free_all(headers);

提交的数据如果有中文,需要URL编码,用curl_easy_escape函数处理。比如:

char* encoded = curl_easy_escape(curl, "张三", 0); std::string encodedStr = encoded; curl_free(encoded);

这里有个隐藏坑:POSTFIELDSIZE的类型是long,数据量超过2GB(不常见但存在)就会出问题,更大数据建议用CURLOPT_POSTFIELDSIZE_LARGE。普通场景不需要在意。

4.5 文件下载和进度显示:调用场景的延伸

libcurl除了发请求,还经常用来下载文件。文件下载本质上就是回调函数不写string,而是写文件句柄:

FILE* fp = fopen("setup.exe", "wb"); curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/setup.exe"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); // 省略自定义回调 curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 直接用libcurl内置的文件写入 // 设置进度回调 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressData); CURLcode res = curl_easy_perform(curl); fclose(fp);

进度回调的写法也有固定套路:

int ProgressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow) { double percent = 0.0; if (dltotal > 0) { percent = (dlnow / dltotal) * 100.0; } // 这里可以更新UI进度条 // 返回非0值会中止传输 return 0; }

这个函数的返回值很关键。如果你的业务逻辑需要在下载中途取消(比如用户点“取消”按钮),设置一个全局标志,然后在回调里检查标志并返回1,libcurl就会中止传输。

5. 编译链接常见错误:把这些“坑”都写进速查表

5.1 “无法打开文件 libcurl.lib”和头文件找不到

这类问题百分之百是路径配错了。VS2013的工程属性里面有两个配置:Debug和Release,你把include路径配在Debug里,Release编译时照样找不到。很多人只改了一个配置,另一个没改,就会遇到“明明配好了却还是报错”的情况。解决办法是:右键项目属性时,先在最上方“配置”下拉框里选“所有配置”,再统一设置路径,就不会漏了。

链接阶段提示“无法打开文件”还有一种可能:libcurl.lib是32位的,工程是64位的(或反过来)。这个看工程属性里的“平台”就知道,x86对应32位,x64对应64位。lib本身是有位数之分的,别混用。

5.2 “无法解析的外部符号 __imp_XXXX”

这个报错的本质是:你告诉编译器要链接libcurl.lib,但编译器在库里找不到对应的函数符号。原因有两类:

第一类,libcurl是静态库,你少加了依赖库。前面说了,静态链接还需要ws2_32.lib、winmm.lib、crypt32.lib、wldap32.lib。这四个缺一不可。VS2013里可以加一行#pragma comment(lib, "ws2_32.lib"),用代码控制链接,挺方便的。

第二类,运行库冲突。libcurl如果是用/MT编译的,你的工程用了/MD,符号解析就可能失败。看编译选项:

#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "winmm.lib") #pragma comment(lib, "crypt32.lib") #pragma comment(lib, "wldap32.lib")

在代码前部加这些编译指令,比在项目属性里配“附加依赖项”更不容易忘。

第三类,libcurl库是用不同版本的MSVC编译的。比如预编译包可能是VS2015编译的,你拿来在VS2013链接,C运行时库的符号对不上。这种情况只能自己重新编译libcurl,用VC=12的makefile。

5.3 运行时报错“应用程序无法正常启动0xc000007b”

这个错误经典到让人头皮发麻。三个字总结就是“不匹配”——libcurl.dll的应用位数和你的exe位数不一致。比如exe是32位的,libcurl.dll是64位的,一跑就报这个。解决思路:确认exe的位数,在x86/x64的LLC里找到对应版本的libcurl.dll。如果还不行,用Dependency Walker(或自带的Dependencies工具)查一下dll的依赖项是否都齐全。

5.4 Debug版本正常、Release版本报错

出现这个,先看两个地方。一是运行时库设置,Debug默认/MTd,Release默认/MT,如果你改了其中一个没改另一个,就会出问题。二是条件编译宏,_DEBUG在Debug里自动定义,Release里没有。如果你在代码里加了#ifdef _DEBUG控制SSL验证之类的逻辑,别忘了检查。

6. 结合VS2013 MFC和OpenCV安装场景:这些问题你迟早会遇到

6.1 MFC程序如何接入libcurl

现在的桌面程序很多还是MFC框架,接入libcurl和Win32控制台工程没有本质区别,但有几个细节要注意。

MFC程序是事件驱动的,你把curl_easy_perform放在按钮的OnBnClicked事件里,点击按钮后界面会卡住,直到请求完成。解决办法是用工作线程:

UINT DownloadThread(LPVOID param) { // 执行libcurl请求 // 通过PostMessage通知主线程更新UI ::PostMessage(hWnd, WM_DOWNLOAD_FINISHED, 0, 0); return 0; } // 在按钮事件里启动线程 AfxBeginThread(DownloadThread, NULL);

一个真实的例子:我在MFC工程里接入libcurl后,本来想把HTTP请求和进度条都放主窗口里跑,结果点击“下载”按钮后整个窗口无响应,进度条卡在0%。改成AfxBeginThread启动后台线程,用PostMessage把进度通知回主线程,界面才正常刷新。

如果用到MFC的调试new宏(DEBUG_NEW),在包含curl头文件的地方可能会报C4996警告,说“localtime安全”之类的。这是因为libcurl的头文件里有些函数在MFC环境中被认为不安全。处理方法是定义CURL_STATICLIB宏,或者把libcurl的头文件include放在MFC标准头文件之后。

6.2 OpenCV和libcurl一起用:给自动采集程序装上传功能

热词里出现了“opencv安装教程vs2013”,这确实是很多人折腾过的组合。OpenCV负责图像采集和识别,libcurl负责把结果上传服务器——这个场景在工业质检、车牌识别、安防监控里非常常见。

如果两个库要在同一个VS2013工程里共存,最容易出现的问题是“符号重复”或“命名空间冲突”。OpenCV是C++库,libcurl是纯C库(虽然提供了C++兼容头文件),两者一般不会冲突。需要注意的还是位数匹配问题:OpenCV和libcurl的库都必须是同一架构(都是32位或都是64位)。

代码层面,常用模式是:OpenCV把图像数据存在std::vector<uchar>里,然后libcurl通过回调函数搬运数据。有个技巧:如果你想POST上传一张图片,可以用CURLOPT_READFUNCTION配合自定义读取回调来发送cv::Mat的内容,这样就不用先存成临时文件再上传,效率高不少。

6.3 卸载不掉VS2013怎么办:一个真实翻车案例

热词里还有“vs2013卸载不掉”,这个我遇到过。有一次想换VS2015,卸载VS2013时卡在“正在卸载Microsoft Visual C++ 2013 Redistributable”,进度条纹丝不动。

试了一下午,最后用微软官方的Visual Studio Uninstaller工具(github上微软官方发布的小工具,搜“vs_installer”就能找到)清理了卸载残留,才勉强搞定。实际操作中,还真的可以试试“先修复再卸载”这个节奏,很多情况下修复能先把损坏的组件补回来,再走卸载流程反而更快。

注意:如果电脑上安装了Microsoft Visual C++ 2013 Redistributable (x64)和(x86)两个版本,卸载VS2013后不要顺手把Redistributable也全删了——有些老软件可能依赖它。我的建议是:保留Redistributable,只卸载IDE部分。

7. 性能优化与多线程:libcurl在实际工程里还能怎么玩

7.1 用multi接口做并发请求

curl_easy_perform是阻塞的,一次只能发一个请求。如果程序需要同时请求多个URL(比如批量查询、并发下载),用easy接口逐个请求,耗时是串行的,效率很糟。

libcurl的multi接口就是干这个的:它允许你同时维护多个easy句柄,在一个线程里非阻塞地调度它们。核心API是curl_multi_add_handlecurl_multi_performcurl_multi_info_read。用multi接口,你甚至不用创建一堆线程,单个线程就能管理几十个并发请求。

我在一个自动批量检查链接有效性的工具里,就是用multi接口同时发50个请求,比单线程快将近50倍(虽然瓶颈在带宽和对方服务器限制上)。

7.2 连接复用和DNS缓存

libcurl默认会对同一个host复用连接,前提是你复用了同一个curl句柄,或者多个句柄共享同一个多接口。如果每次请求都创建新句柄、销毁旧句柄,每次都得重新TCP握手、TLS握手,那性能就白丢了一截。

合理做法:把curl句柄定义成局部变量,但在循环体外创建,循环内只改URL、POST数据,执行完不要清理句柄,留着复用。我见过一些半年经验的程序员在循环里频繁curl_easy_initcurl_easy_cleanup,每次请求都慢100毫秒以上。不用太在意,稍加调整就能把性能追回来。

DNS缓存方面,设置了CURLOPT_DNS_CACHE_TIMEOUT可以控制DNS解析结果缓存时间,默认60秒。如果访问的是内网IP地址或固定IP服务,可以考虑设大一些,比如300秒,减少重复DNS查询。

7.3 断点续传和限速

下载大文件时,支持断点续传是个很实用的功能:

// 从偏移量offset开始下载,假设之前已下载了1000字节 curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, 1000L);

上传文件也类似,用CURLOPT_INFILESIZE_LARGE告诉服务端文件大小。注意,断点续传需要服务端支持Range头,大部分现代Web服务器默认支持。

限速用CURLOPT_MAX_RECV_SPEED_LARGECURLOPT_MAX_SEND_SPEED_LARGE,单位是字节/秒。比如想限制下载速度不超过200KB/s:

curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, 200 * 1024);

这个功能在实际场景里很关键——特别是需要同时跑多个网络任务时,不限速会吃满带宽,影响其他业务。

8. 最后分享一个小经验:先跑通再说优化

我见过很多人在图省事和追求完美之间反复横跳,最后卡在第一步。做这个VS2013 + libcurl的示例工程,我的建议是:先让它跑起来,看到控制台输出了HTTP状态码和响应内容,然后你再慢慢去优化细节。

具体说,第一件事是把环境配置全部搞定,Debug和Release都能编译通过,这是最重要的一步。第二件事是定一个小目标,比如“成功请求一个API并输出返回的JSON字符串”,目标定得越小越容易达成。第三件事才考虑封装、多线程、性能优化这些东西。

再分享一个调试技巧:用libcurl经常遇到“请求发出去但服务端没收到”的情况。先用抓包工具确定请求有没有真正发出,如果没有,十有八九是链接配置问题;如果有但服务端报错,检查Content-Type、User-Agent等头部字段。我发现很多奇怪问题其实出在User-Agent上,有些服务端会拦截空UA的请求,直接设置一个常规UA能省掉不少麻烦:

curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64)");

希望这些操作经验能帮你少走点弯路。VS2013虽然老,但搭配libcurl依然能干活,而且是很多老项目的救星。有问题欢迎交流,我尽量有空就回复。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 7:37:33

BCB6运行库与DLL部署实战:从动态链接原理到常见报错排查

简介&#xff1a;面向 BCB 6.0 开发者的运行库合集&#xff0c;专注于解决 Borland C Builder 6 开发的程序在未安装完整开发环境中无法启动或依赖缺失的问题&#xff0c;适合维护旧项目、制作绿色版软件或发布安装包的场景。压缩包总大小 35.22MB&#xff0c;共 306 个文件&am…

作者头像 李华
网站建设 2026/9/8 7:34:56

WebSocket 测试实战:工具选型、脚本化与性能压测全攻略

简介&#xff1a;这是一款面向开发者的 WebSocket 通信测试工具包&#xff0c;适用于需要验证服务端与客户端连接、调试实时应用&#xff08;如在线聊天、协同编辑、股票行情推送&#xff09;的工程师。压缩包共19个文件&#xff0c;约2.87MB&#xff0c;包含可直接运行的exe客…

作者头像 李华
网站建设 2026/9/8 7:34:53

流量激励算法解析:从技术本质到内容策略优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 7:34:03

2048前端项目拆解:从zip包到游戏逻辑与定制部署

简介&#xff1a;2048-html5.zip是一份以经典2048数字合成游戏为载体的HTML5前端开发源码&#xff0c;适合Web前端初学者、游戏开发爱好者&#xff0c;以及希望快速理解Canvas绘图、JavaScript游戏逻辑和Web存储应用的开发者。压缩包共4个文件&#xff0c;分别承担页面结构、样…

作者头像 李华
网站建设 2026/9/8 7:34:00

蓝牙物联网助力医疗监测革命:从协议选型到工程实践

我在医院信息化项目里摸爬滚打了好几年&#xff0c;最大的感受是&#xff1a;护士站测体温这件事在过去完全靠人力。一个人端个托盘挨个病床跑&#xff0c;测完再抄到护理单上&#xff0c;一天两三次已经算高频&#xff0c;更别说半夜的体温异常往往到第二天交班才被发现。但这…

作者头像 李华
网站建设 2026/9/8 7:33:00

揭秘内存墙:从存储层次到算子优化的性能瓶颈与拆墙实践

跑GEMM类算子的时候&#xff0c;芯片利用率轻松到70%甚至80%&#xff1b;一旦切到真实模型推理&#xff0c;整体利用率常常掉到20%上下。这个现象干过AI芯片或性能优化的人应该都不陌生。我入行头两年也被这个问题折磨得够呛&#xff0c;总以为是框架调度不行&#xff0c;或者是…

作者头像 李华