curl 库 CURLINFO_SIZE_UPLOAD_T 完全指南:精确统计上传字节数
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
导读
CURLINFO_SIZE_UPLOAD_T是 libcurl 提供的运行时统计接口,用于在请求完成后读取本次传输实际上传的总字节数。它在 curl 项目(GitHub_Trending/cu/curl)中广泛应用于进度展示、限速与断点续传等场景——无论是用curl_easy_perform完成的一次性上传,还是基于curl_multi的并发上传任务,都能通过它拿到精确的curl_off_t类型计数。读完本文,你将掌握该选项的完整用法、与旧版CURLINFO_SIZE_UPLOAD的区别、底层数据来源,以及如何在真实代码中正确获取与格式化上传字节数。
接口速览
函数原型
#include <curl/curl.h> CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD_T, curl_off_t *uploadp);handle:已初始化并完成一次curl_easy_perform(或 multi 接口驱动)传输的 easy handle。uploadp:指向curl_off_t的指针,函数执行成功后,此处写入本次传输累计上传的字节总数。- 返回值:
CURLcode状态码,CURLE_OK表示成功,非零表示出错(具体错误参见 libcurl-errors)。
类型定义(头文件中的枚举值)
在 include/curl/curl.h 中可以看到该选项在CURLINFO枚举中的定义:
CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T") = CURLINFO_DOUBLE + 7, CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7,其中CURLINFO_OFF_T(0x600000)是 64 位有符号整数类型的标记位,CURLINFO_DOUBLE(0x300000)是双精度浮点标记位。这从编译期就决定了新旧两个选项的输出数据类型不同:旧版CURLINFO_SIZE_UPLOAD返回double,新版CURLINFO_SIZE_UPLOAD_T返回curl_off_t。CURL_DEPRECATED(7.55.0, ...)宏表明旧接口自 7.55.0 起被标记为废弃,官方建议一律改用_T后缀版本。
基本用法:读取上传字节数
以下代码完整演示了获取上传字节数的标准流程,示例同时用于 PUT/POST 等上传场景:
#include <stdio.h> #include <curl/curl.h> int main(void) { CURL *curl = curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); /* Perform the request */ result = curl_easy_perform(curl); if(result == CURLE_OK) { curl_off_t ul; result = curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD_T, &ul); if(result == CURLE_OK) { printf("Uploaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", ul); } } curl_easy_cleanup(curl); } return 0; }要点说明:
- 调用时机:必须在该 easy handle 完成传输之后(例如
curl_easy_perform返回之后)调用,否则读到的仍是上一次或未初始化的值。在 multi 接口中,应在CURLMSG_DONE消息回调或curl_multi_info_read返回该 transfer 完成状态之后再查询。 - 返回值检查:
curl_easy_getinfo的返回值同样需要检查,即使perform成功,getinfo 也可能因参数类型不匹配等原因返回错误。 - 类型与格式化:
curl_off_t通常是 64 位有符号整数,不能直接用%d/%ld打印(不同平台宽度可能不同),应使用头文件提供的CURL_FORMAT_CURL_OFF_T格式化宏以保证可移植性。 - 计数语义:统计的是“实际上传”的字节数,即写入协议的数据量;对 HTTP 而言包括请求体(如 PUT/POST 的 body)等上行数据,但不包括协议头(header)部分。该值遵循
CURLINFO_OFF_T类型,可表示超大文件的上传量而不受double精度损失影响。
与 CURLINFO_SIZE_UPLOAD(旧版)的对比
| 对比项 | CURLINFO_SIZE_UPLOAD(废弃) | CURLINFO_SIZE_UPLOAD_T(推荐) |
|---|---|---|
| 引入版本 | 7.4.1 | 7.55.0 |
| 输出类型 | double * | curl_off_t * |
| 精度 | 大数(如超过 2^53 字节)存在精度损失 | 64 位整数,无损 |
| 状态 | 自 7.55.0 起CURL_DEPRECATED | 当前推荐接口 |
旧版定义参见 docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md,其内部实现*param_doublep = (double)data->progress.ul.cur_size;(见 lib/getinfo.c)会将 64 位计数强转成double,当上传量超过double精确表示范围(约 9 PB)时不再精确;新版则直接返回data->progress.ul.cur_size的原始curl_off_t值(见 lib/getinfo.c)。因此凡是上传量可能很大的场景,都应使用_T版本。
底层实现:数据从哪来
CURLINFO_SIZE_UPLOAD_T不是独立维护的计数器,而是直接读取 easy handle 内部进度结构体struct Progress中上传方向的累计值。整个数据链路如下:
- 存储位置:
struct Progress内包含上传方向统计子结构struct pgrs_dir ul,其成员cur_size即“已传输字节数”(见 lib/urldata.h):
struct pgrs_dir { curl_off_t total_size; /* total expected bytes */ curl_off_t cur_size; /* transferred bytes so far */ curl_off_t speed; /* bytes per second transferred */ struct Curl_rlimit rlimit; /* speed limiting / pausing */ };- 计数累加:传输过程中,各协议过滤器(filter)每写出
delta字节,都会调用进度模块的Curl_pgrs_upload_inc()将data->progress.ul.cur_size += delta(见 lib/progress.c);另有Curl_pgrsSetUploadCounter()用于直接设置当前上传计数值(见 lib/progress.c)。 - 读取返回:
curl_easy_getinfo内部在CURLINFO_SIZE_UPLOAD_T分支直接返回*param_offt =>curl_off_t sent, expected; curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD_T, &sent); curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &expected); if(expected >= 0 && sent != expected) fprintf(stderr, "Upload incomplete: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T " bytes\n", sent, expected);2. 配合上传选项使用
CURLINFO_SIZE_UPLOAD_T通常与以下上传相关选项配合,构成完整的上传流程:CURLOPT_UPLOAD:开启上传模式(如 FTP 上传、HTTP PUT)。CURLOPT_POSTFIELDS/CURLOPT_POSTFIELDSIZE/CURLOPT_POSTFIELDSIZE_LARGE:指定 POST 数据及长度(_LARGE版本使用curl_off_t,与本文类型一致)。CURLOPT_READFUNCTION与CURLOPT_READDATA:自定义上传数据读取回调。CURLOPT_INFILESIZE_LARGE:告知服务器上传文件大小。CURLOPT_RESUME_FROM_LARGE:断点续传偏移,配合续传完成后用本选项核对已传总量。
各选项的详细说明见 docs/libcurl/opts 目录,例如
CURLOPT_UPLOAD.md、CURLOPT_INFILESIZE_LARGE.md。3. 在 multi 接口中统计并发上传
在多句柄并发场景下,每个 easy handle 独立维护自己的
ul.cur_size,因此可在每个 transfer 完成(CURLMSG_DONE)后分别查询,再汇总得到整体上传量,互不干扰。注意事项与易错点
- 必须在传输完成后读取:传输进行中读取可能得到 0 或中间值;重用一个 easy handle 发起第二次传输前,值会在新传输初始化时被清零(见 lib/progress.c)。
- 类型必须匹配:
_T版本必须传入curl_off_t *,旧版必须传入double *。混用会导致内存越界写入(类型大小不同),属于未定义行为。 - 统计范围是“已发送的应用数据”:不包含协议头;对分块传输(chunked)等场景,计数的是 payload 字节。
- 旧版精度问题:不要在新代码中使用
CURLINFO_SIZE_UPLOAD;即使旧代码,也建议迁移到_T版本。 - 版本要求:该接口自 libcurl 7.55.0 引入(见文档头部
Added-in: 7.55.0字段),使用前需确认链接的 libcurl 版本满足要求。
小结
CURLINFO_SIZE_UPLOAD_T是 libcurl 获取上传字节数的事实标准接口:它以 64 位整数精确返回每次传输的上传总量,底层直接读取进度模块ul.cur_size计数器,与速率、长度等_T系列接口协同可完整刻画上传过程。在实践中记住三点即可用得准确:传输完成后查询、传curl_off_t *、用CURL_FORMAT_CURL_OFF_T打印。更多细节可参考 docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md 与配套的 curl_easy_getinfo 文档。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features
项目地址: https://gitcode.com/GitHub_Trending/cu/curl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考