curl libcurl 实战:CURLINFO_PRETRANSFER_TIME_T 微秒级传输启动时间详解与源码剖析
curl libcurl 实战CURLINFO_PRETRANSFER_TIME_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本篇围绕 libcurl 的信息查询选项CURLINFO_PRETRANSFER_TIME_T展开它返回从传输开始到“文件传输即将开始”之间的微秒级耗时涵盖所有协议相关的预传输命令与协商如 FTP 的路径切换、认证握手指令等。读完本文你将理解该时间戳的语义边界、与其他时间指标CONNECT、APPCONNECT、STARTTRANSFER 等的层级关系并能结合 curl 源码计时器状态机、curl_easy_getinfo取值路径与 curl 命令行-w变量在性能诊断场景中准确使用这一指标。一、它是什么传输启动前的累计耗时微秒CURLINFO_PRETRANSFER_TIME_T是curl_easy_getinfo(3)的一个查询项用于获取“传输开始到传输即将开始”的耗时。其原型与用法如下见 CURLINFO_PRETRANSFER_TIME_T 手册#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRETRANSFER_TIME_T, curl_off_t *timep);关键语义有三点单位是微秒接收类型是 64 位整数curl_off_t *。这是 7.61.0 版本新增的_Toff_t系列时间查询项之一专门替代旧的double秒级接口CURLINFO_PRETRANSFER_TIME避免浮点精度问题毫秒级以下的差异在double秒值中会被放大为噪声。它包含所有协议特定的预传输命令与协商。官方描述为该时间戳包含所有与所涉协议相关的预传输命令和协商包括触发传输的协议特定指令的发送。例如 FTP 场景下的用户认证、CWD切目录、SIZE询问等FTP over TLS 的控制连接切换等。也就是说它衡量的是“连接就绪之后、数据真正开始流动之前”这一段协议层开销。遵循重定向会累加。当跟随重定向CURLOPT_FOLLOWLOCATION时每个请求的这部分时间会被累加到一起而非只返回最后一跳的值。该选项对所有协议生效%PROTOCOLS%标注为 All自7.61.0版本起可用。二、在时间轴中的位置TIMES 层级CURLINFO_PRETRANSFER_TIME_T并非孤立指标curl_easy_getinfo(3)手册中给出了全部时间值的层级总览见 curl_easy_getinfo 手册 TIMES 一节curl_easy_perform() | |--QUEUE |--|--NAMELOOKUP |--|--|--CONNECT |--|--|--|--APPCONNECT |--|--|--|--|--PRETRANSFER |--|--|--|--|--|--POSTTRANSFER |--|--|--|--|--|--|--STARTTRANSFER |--|--|--|--|--|--|--|--TOTAL |--|--|--|--|--|--|--|--REDIRECT这是一棵累计嵌套的时间树NAMELOOKUP包含 DNS 解析CONNECT包含到 TCP 建连为止的全部时间APPCONNECT再叠加应用层连接典型为 TLS 握手而PRETRANSFER又包含前述所有阶段再加上协议协商。因此PRETRANSFER - APPCONNECTHTTPS 场景大致等于纯协议层预传输开销PRETRANSFER - CONNECT纯 HTTP 场景基本就是请求头发送前的最后协商耗时STARTTRANSFER - PRETRANSFER则近似于“从传输启动到收到第一个字节”的服务端响应延迟TTFB 的近似值。对应的手册文档与枚举定义一一对应源码中枚举位于 curl.hCURLINFO_TOTAL_TIME_T CURLINFO_OFF_T 50, CURLINFO_NAMELOOKUP_TIME_T CURLINFO_OFF_T 51, CURLINFO_CONNECT_TIME_T CURLINFO_OFF_T 52, CURLINFO_PRETRANSFER_TIME_T CURLINFO_OFF_T 53, CURLINFO_STARTTRANSFER_TIME_T CURLINFO_OFF_T 54, CURLINFO_REDIRECT_TIME_T CURLINFO_OFF_T 55,三、完整示例查询并格式化输出微秒时间手册给出的示例可直接复制运行需要链接 libcurlint main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_off_t pretransfer; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/); result curl_easy_perform(curl); if(result CURLE_OK) { result curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME_T, pretransfer); if(result CURLE_OK) { printf(Time: % CURL_FORMAT_CURL_OFF_T .%06ld\n, pretransfer / 1000000, (long)(pretransfer % 1000000)); } } /* always cleanup */ curl_easy_cleanup(curl); } }输出形如Time: 1.034217即 1 秒 034217 微秒。CURL_FORMAT_CURL_OFF_T是随平台自适应的printf长度修饰符64 位平台上为PRId64的等价形式保证curl_off_t正确打印。四、源码剖析这个值从哪里来4.1 取值路径curl_easy_getinfo直接读取进度统计在 getinfo.c 中CURLINFO_PRETRANSFER_TIME_T的取值极其直接——返回内部进度结构中的微秒累计值case CURLINFO_PRETRANSFER_TIME_T: *param_offt >case CURLINFO_PRETRANSFER_TIME: *param_doublep DOUBLE_SECS(data-progress.total.pretransfer_us); break;其中#define DOUBLE_SECS(x) ((double)(x) / 1000000)。这解释了为什么手册建议使用_T变体底层就是整数微秒double 接口反而是降精度的。存储字段定义在 urldata.htimediff_t pretransfer_us; /* same until requests were sent */4.2 打点机制Curl_pgrsTimeWas与 TIMER_PRETRANSFER真正“写入”这个值的是通用计时器打点函数Curl_pgrsTimeWas()位于 progress.c。它把各阶段计时器映射到progress.total中对应的微秒字段case TIMER_PRETRANSFER: delta data-progress.total.pretransfer_us; break;随后同函数 L329-L337 的通用收尾逻辑计算当前时刻 - 传输开始时刻 - 本次 single 传输起点得到增量并累加到*delta且保证至少 1 微秒if(us 1) us 1。这个“累加”行为正是文档所说“重定向时间相加”的实现基础每一次重定向都会重新走一遍TIMER_NAMELOOKUP…TIMER_PRETRANSFER的打点序列增量叠加进同一个total字段。在开启CURLVERBOSE的调试构建中打点日志会打印PGRS-PRETRANSFER标签progress.c配合curl -v可以直观看到计时器触发顺序。4.3 触发时机状态机进入MSTATE_DID时打点TIMER_PRETRANSFER的触发点集中在 multi 引擎的状态机中multi.cstatic void mstate_enter_did(struct Curl_easy *data, CURLMstate from_state) { (void)from_state; >if(from_state MSTATE_DID) { Curl_pgrsTime(data, TIMER_PRETRANSFER); Curl_pgrsTime(data, TIMER_POSTRANSFER); Curl_pgrsTime(data, TIMER_STARTTRANSFER); }4.4 与Curl_pretransfer()的区分需要注意区分两个同名概念TIMER_PRETRANSFER计时器与传输层函数Curl_pretransfer()transfer.c。后者注释说明它“在传输即将开始时被调用且无论有无重定向或多轮认证一次传输只调用一次”负责初始化 URL、方法、重试计数等传输参数而计时器记录的是“进入数据转移阶段”这一时刻。二者协作定义了文档中“until the file transfer is about to begin”的语义从curl_easy_perform()开始扣除队列等待直到传输参数就绪、数据即将收发。五、实战应用5.1 curl 命令行的%{time_pretransfer}curl 命令行工具将本指标暴露为 write-out 变量注册表见 tool_writeout.c{ time_pretransfer, VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T, writeTime },因此无需写 C 代码一条命令即可在微秒级精度下对比“协议协商”与“传输开始”的耗时curl -o /dev/null -s -w pretransfer%{time_pretransfer}s starttransfer%{time_starttransfer}s\n \ https://example.com/writeTime回调内部以毫秒为步长对微秒值做截断格式化与 C API 返回的原始微秒值存在显示精度差异精确到微秒的场景请走curl_easy_getinfo。5.2 传输过程中即可查询回调内读取该指标在传输尚未结束时就有值。仓库回归测试 lib1541.c 在收到首个响应头的回调中即调用curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME_T, ...)并断言其有效/* first header, check some CURLINFO value to be reported. See #13125 */ check_time(st-curl, KN(CURLINFO_CONNECT_TIME_T), 1st header); check_time(st-curl, KN(CURLINFO_PRETRANSFER_TIME_T), 1st header); check_time(st-curl, KN(CURLINFO_STARTTRANSFER_TIME_T), 1st header);对应的测试定义文件 test1541 验证了“1st header”与“done”两个时点取值均 OK。这意味着你可以把CURLINFO_PRETRANSFER_TIME_T用于流式场景在 header 回调里拿到该值即可在数据开始下载的瞬间估算本次请求的完整前置开销此时 PRETRANSFER 与 STARTTRANSFER 已定型而 TOTAL 尚未结束。5.3 调试构建中的CURL_TIME环境覆盖在 DEBUGBUILD 构建下getinfo.c 对所有_T时间查询项支持CURL_TIME环境变量强制覆盖返回值用于单元测试中屏蔽真实时钟波动。这是构建级调试特性发布版无此行为生产环境请勿依赖。六、返回值与错误处理curl_easy_getinfo(3)返回CURLcodeCURLE_OK (0)表示成功非零表示出错详见 libcurl-errors 手册。对CURLINFO_PRETRANSFER_TIME_T而言传入参数不是curl_off_t *或 handle 无效时会返回相应错误码查询成功的典型错误路径只有参数不匹配。示例中的双重if(result CURLE_OK)判空写法perform 一次、getinfo 一次是推荐范式。七、相关查询项速查查询项单位/类型语义与 PRETRANSFER 的关系CURLINFO_PRETRANSFER_TIME_T微秒 /curl_off_t到传输即将开始含协议协商重定向累加本文主角CURLINFO_PRETRANSFER_TIME秒 /double同上旧版浮点接口同源数据精度较低CURLINFO_APPCONNECT_TIME_T微秒 /curl_off_t到应用层连接TLS 握手完成通常 ≤ PRETRANSFERCURLINFO_STARTTRANSFER_TIME_T微秒 /curl_off_t到收到第一个字节通常 ≥ PRETRANSFERCURLINFO_TOTAL_TIME_T微秒 /curl_off_t到传输全部结束≥ STARTTRANSFER以上层级关系在 curl_easy_getinfo.md 的 TIMES 总览 中有权威图示。做延迟归因时建议一次性取齐 CONNECT / APPCONNECT / PRETRANSFER / STARTTRANSFER / TOTAL 五个_T值通过相邻相减定位瓶颈段DNS、TCP/TLS、协议协商、服务端响应、数据传输。小结CURLINFO_PRETRANSFER_TIME_T7.61.0 引入全协议适用以微秒为单位的 64 位整数返回从传输启动到“文件传输即将开始”的累计耗时涵盖 FTP 认证/切目录等协议特定协商指令重定向跟随时各跳耗时累加实现上由 multi 状态机进入MSTATE_DID时打点TIMER_PRETRANSFER完成multi.c、progress.c取值路径见 getinfo.c命令行下等价于-w %{time_pretransfer}tool_writeout.c该值在传输过程中首个响应头回调时即可读取参考 lib1541.c适合流式场景的实时延迟诊断建议与 CONNECT、APPCONNECT、STARTTRANSFER、TOTAL 组合做差值归因完整层级见 TIMES 总览。【免费下载链接】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),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →