libcurl 定时器详解:CURLINFO_APPCONNECT_TIME 与 SSL/SSH 握手计时原理

发布时间:2026/9/10 9:15:38
libcurl 定时器详解:CURLINFO_APPCONNECT_TIME 与 SSL/SSH 握手计时原理 libcurl 定时器详解CURLINFO_APPCONNECT_TIME 与 SSL/SSH 握手计时原理【免费下载链接】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导读本文聚焦 curl 项目中 libcurl 提供的一项核心诊断指标——CURLINFO_APPCONNECT_TIME它精确度量从传输开始到 SSL/SSH 连接握手完成所消耗的秒数。无论你是排查 HTTPS 请求握手延迟、对比不同 TLS 后端的性能还是想基于 curl 命令行工具 的-w输出解析握手耗时掌握这个选项及其配套的CURLINFO_APPCONNECT_TIME_T微秒级版本都至关重要。读完本文你将理解该时间戳的语义边界、它与CURLINFO_PRETRANSFER_TIME等指标的关系、底层源码中的记录机制以及如何在自己的 C 程序与 shell 脚本中正确读取它。1. 选项定位与基本语义1.1 它是什么CURLINFO_APPCONNECT_TIME是 libcurl 通过curl_easy_getinfo(3)返回的传输计时指标之一语义为从请求开始到与远程主机的SSL/SSH 连接握手完成所经过的时间单位秒double类型。这里的应用层连接Application Connect特指 TLS/SSL 握手或 SSH 连接建立过程与更底层的 TCP 连接计时CURLINFO_CONNECT_TIME相互区分。该选项适用于 curl 支持的所有协议包括 HTTP/HTTPS、FTP/FTPS、IMAP/IMAPS 等官方文档声明Protocol: All。1.2 历史版本CURLINFO_APPCONNECT_TIME自 libcurl7.19.0起提供见 CURLINFO_APPCONNECT_TIME.md 头部的Added-in字段微秒精度的CURLINFO_APPCONNECT_TIME_T自7.61.0起提供见 CURLINFO_APPCONNECT_TIME_T.md 头部。在公开头文件 include/curl/curl.h 中可以看到两者的枚举定义分别属于不同类型族CURLINFO_APPCONNECT_TIME CURLINFO_DOUBLE 33, /* 秒double */ CURLINFO_APPCONNECT_TIME_T CURLINFO_OFF_T 56, /* 微秒curl_off_t */2. 使用方法与代码示例2.1 函数原型#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_APPCONNECT_TIME, double *timep);调用约束handle必须是已经执行过curl_easy_perform()或 multi 接口传输的 easy handle因为计数值是在传输过程中逐步记录的timep指向一个double变量函数会将秒数写入该变量返回值是CURLcodeCURLE_OK0表示成功非零值表示出错详见 libcurl-errors(3) 一节。2.2 完整示例来自官方文档int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; double connect; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/); result curl_easy_perform(curl); if(result CURLE_OK) { result curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, connect); if(result CURLE_OK) { printf(Time: %.1f, connect); } } /* always cleanup */ curl_easy_cleanup(curl); } }注意示例中的输出格式%.1f只打印一位小数由于返回值以秒为单位若需要毫秒/微秒级展示可自行乘 1000 / 1000000或直接改用_T变体见 2.4 节。2.3 使用_T微秒变体当需要更高精度微秒时使用CURLINFO_APPCONNECT_TIME_T其输出类型为curl_off_tint main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_off_t connect; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/); result curl_easy_perform(curl); if(result CURLE_OK) { result curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME_T, connect); if(result CURLE_OK) { printf(Time: % CURL_FORMAT_CURL_OFF_T .%06ld, connect / 1000000, (long)(connect % 1000000)); } } /* always cleanup */ curl_easy_cleanup(curl); } }微秒值用CURL_FORMAT_CURL_OFF_T格式化curl_off_t秒与微秒部分分别取整除与取模官方文档在 curl_easy_getinfo(3) 的 TIMES 一节确认CURLINFO_APPCONNECT_TIME_T提供的是微秒数。2.4 秒级与微秒级如何选择选项类型单位引入版本适用场景CURLINFO_APPCONNECT_TIMEdouble秒7.19.0日志、概览统计CURLINFO_APPCONNECT_TIME_Tcurl_off_t微秒7.61.0高精度计时、性能剖析两者读取的是同一个底层计数值源码见第 4 节只是单位与类型不同选择依据是精度需求与你的程序类型体系。3. 语义细节与易混淆点3.1 与 CURLINFO_PRETRANSFER_TIME 的关系文档明确指出这个时间通常与CURLINFO_PRETRANSFER_TIME非常接近但在 HTTP 多路复用HTTP/2、HTTP/3 multiplexing场景下pre-transfer 时间可能因为流排队等待而显著延后。原因在于APPCONNECT在 TLS/SSH 握手完成的瞬间打点PRETRANSFER在请求即将真正发出可发送数据时才打点若连接需在流队列中等待二者会出现明显差距。因此如果你想衡量纯握手耗时APPCONNECT是更干净、更接近真实握手的指标。3.2 重定向时的累加语义文档明确当发生重定向时每次请求的该时间会被累加。即最终读到的是多次请求握手耗时的总和而非最后一次或最大的一次。这在分析多跳重定向链路的总耗时时要特别留意可与CURLINFO_REDIRECT_COUNT、CURLINFO_REDIRECT_TIME结合解读。3.3 计时起点所有 libcurl 时间指标都以传输开始curl_easy_perform内部的TIMER_STARTOP时刻为基准而不是程序启动时刻。CURLINFO_APPCONNECT_TIME度量的是从该起点到握手完成的间隔。整个时间线在 curl_easy_getinfo.md 的 TIMES 一节中有清晰的层级图curl_easy_perform() | |--QUEUE |--|--NAMELOOKUP |--|--|--CONNECT |--|--|--|--APPCONNECT |--|--|--|--|--PRETRANSFER |--|--|--|--|--|--POSTTRANSFER |--|--|--|--|--|--|--STARTTRANSFER |--|--|--|--|--|--|--|--TOTAL |--|--|--|--|--|--|--|--REDIRECT即典型的 HTTPS 请求时间线为QUEUE → NAMELOOKUP → CONNECTTCP→APPCONNECTTLS→ PRETRANSFER → STARTTRANSFER → TOTAL。4. 源码级实现剖析4.1 打点位置谁在写appconnect_us计时值最终存储在 easy handle 的data-progress.total.appconnect_us字段中该字段在 lib/urldata.h 中定义timediff_t appconnect_us; /* same for application connects, e.g. TLS */围绕这一字段libcurl 在不同协议栈中通过Curl_pgrsTime(data, TIMER_APPCONTECT)/Curl_pgrsTimeWas(...)记录打点timer 枚举定义在 lib/progress.hTLS/SSLvtls 层在 lib/vtls/vtls.c 中SSL 握手完成connssl-handshake_done时调用Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl-handshake_done)且通过connssl-stats_reported保证每个连接只上报一次SSHlibssh / libssh2认证完成后在 lib/vssh/libssh.c 与 lib/vssh/libssh2.c 直接调用Curl_pgrsTime(data, TIMER_APPCONNECT)注释明确写着 SSH is connectedQUIC/HTTP3ngtcp2 / quiche分别在 lib/vquic/cf-ngtcp2-cmn.c 与 lib/vquic/cf-quiche.c 用握手完成时刻handshake_at打点Happy Eyeballs 连接竞速cf-ip-happy.c在 SSH 协议族且胜出连接已建立时于 lib/cf-ip-happy.c 打点。这些打点最终都汇聚到Curl_pgrsTimeWas()lib/progress.c其中TIMER_APPCONNECT分支把delta指向data-progress.total.appconnect_us实现累加case TIMER_APPCONNECT: delta data-progress.total.appconnect_us; break;4.2 读取路径getinfo 如何返回给用户curl_easy_getinfo内部按选项类型分派秒级CURLINFO_APPCONNECT_TIME走getinfo_double()lib/getinfo.c通过DOUBLE_SECS(x)(double)(x) / 1000000定义于 lib/getinfo.c把微秒计数值换算为秒case CURLINFO_APPCONNECT_TIME: *param_doublep DOUBLE_SECS(data-progress.total.appconnect_us); break;微秒级CURLINFO_APPCONNECT_TIME_T走getinfo_offt()lib/getinfo.c直接原样返回微秒数case CURLINFO_APPCONNECT_TIME_T: *param_offt >curl -o /dev/null -s -w appconnect: %{time_appconnect}s\ntotal: %{time_total}s\n https://example.com/变量time_appconnect对应的正是CURLINFO_APPCONNECT_TIME_T见 src/tool_writeout.c 中{ time_appconnect, VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T, writeTime }的映射在 docs/cmdline-opts/write-out.md 中有同样定义它表示从开始到与远程主机的 SSL/SSH 连接/握手完成所经过的秒数。结合%{time_connect}TCP 连接耗时与%{time_namelookup}DNS 解析耗时即可快速拆解 HTTPS 请求各阶段耗时定位瓶颈在 DNS、TCP 还是 TLS 握手。6. 常见问题与注意事项返回值只在传输成功后可信若curl_easy_perform失败如握手失败、连接被拒应优先检查返回码计时值可能不完整或为 0。非 TLS/SSH 协议返回 0文档声明Protocol: All表示该选项在所有协议下都可查询但只有经过 SSL/SSH 握手的传输才会有非零值测试 tests/libtest/lib1541.c 已证实。单位与精度陷阱秒级版本是double微秒版本是curl_off_t两者来自同一计数注意不要混淆类型用_T版本做精确比较与统计更稳妥。重定向累加多跳重定向下该值是各次请求之和解读单次握手耗时前需确认是否存在重定向结合CURLINFO_REDIRECT_COUNT。版本前提使用CURLINFO_APPCONNECT_TIME需要 libcurl ≥ 7.19.0使用_T变体需要 ≥ 7.61.0编译时可用LIBCURL_VERSION_NUM做版本判断。7. 相关参考本选项文档docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md微秒变体文档docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md获取接口总览含 TIMES 时间线docs/libcurl/curl_easy_getinfo.md计时器打点实现lib/progress.c、lib/progress.h返回值分派实现lib/getinfo.c命令行-w变量docs/cmdline-opts/write-out.md、src/tool_writeout.c【免费下载链接】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),仅供参考