ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

libcurl CURLINFO_PRIVATE:如何从 curl handle 中取回应用私有数据指针

libcurl CURLINFO_PRIVATE:如何从 curl handle 中取回应用私有数据指针 libcurl CURLINFO_PRIVATE如何从 curl handle 中取回应用私有数据指针【免费下载链接】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 仓库官方手册页 CURLINFO_PRIVATE 展开讲清CURLINFO_PRIVATE这个curl_easy_getinfo(3)选项的用法、与CURLOPT_PRIVATE的配对关系并结合当前仓库源码说明私有指针在 libcurl 内部的存储与取回路径。读完后你将能够在回调函数、multi 并发场景下可靠地定位每个 handle 对应的应用层上下文结构并理解返回值为char *却实际是void *的类型怪癖及正确处理姿势。选项速览选项名CURLINFO_PRIVATE枚举定义为CURLINFO_STRING 21见 include/curl/curl.h#L2971配套设置项CURLOPT_PRIVATE存入私有指针两者必须成对理解另见 CURLOPT_PRIVATE 手册页默认值NULL从未设置过时取回的指针为NULL适用协议All与协议无关属于 handle 级元数据引入版本libcurl 7.10.3SYNOPSIS函数原型按照官方手册页该选项的调用形式为#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIVATE, char **private);注意第三个参数是char **——你必须传入一个指向char *变量的地址。这对应了手册页 DESCRIPTION 中的一段关键说明Pass a pointer to a char pointer to receive the pointer to the private data associated with the curl handle (set with the CURLOPT_PRIVATE(3)). Please note that for internal reasons, the value is returned as a char pointer, although effectively being a void *.即libcurl 因为内部原因把值以char *的形式返回但它实际上就是你设置进去的那个void *。在 C 语言中char *与任意对象指针尺寸相同因此把取回的char *再转回原来的结构体指针类型是安全且惯用的做法。源码级原理私有指针在 libcurl 中如何流转CURLINFO_PRIVATE之所以“零成本”是因为 libcurl 本身从不读写、拷贝或解释这块数据——它只是一个不透明指针的存取器。这一点可以从当前仓库源码得到印证整条链路只有三步1. 存储curl_easy_setopt只做一次指针赋值在 lib/setopt.c#L2379-L2381 中CURLOPT_PRIVATE的处理分支是全部 setopt 选项中最简洁的之一case CURLOPT_PRIVATE: s-private_data ptr; break;没有内存分配、没有深拷贝、没有校验。这与 CURLOPT_PRIVATE 手册页 中“libcurl itself never does anything with this data”libcurl 自身从不处理这份数据的声明完全一致。在选项表中lib/easyoptions.c#L214 将其归类为CURLOT_OBJECT类型即接收任意对象指针。2. 存放位置easy handle 的设置结构体这个指针存放在每个 easy handle 内部的struct Curl_easy设置区中。在 lib/urldata.h#L908 可以看到字段定义void *private_data; /* application-private data */从源码结构看private_data是Curl_easy级而非连接级字段连接复用、重定向切换都不会改变它它跟随 handle 生命周期一直存在。3. 取回curl_easy_getinfo直接返回原指针在 lib/getinfo.c#L121-L123 中CURLINFO_PRIVATE的取值分支同样只有一行实质代码case CURLINFO_PRIVATE: *param_charp (const char *)data-set.private_data; break;*param_charp就是你传入的char **所指向的变量被直接赋值为当初CURLOPT_PRIVATE存入的那个void *加了const char *转换以匹配接口签名。没有任何中间副本因此返回的指针值与设置时的值严格相等——这也意味着如果设置之后你修改了指向的对象内容回调里通过CURLINFO_PRIVATE取回的指针读到的就是最新内容。官方示例设置与取回一个私有指针手册页给出的完整示例演示了“setopt 存入 → perform 传输 → getinfo 取回”的最小闭环int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; void *pointer (void *)0x2345454; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/foo.bin); /* set the private pointer */ curl_easy_setopt(curl, CURLOPT_PRIVATE, pointer); result curl_easy_perform(curl); /* extract the private pointer again */ result curl_easy_getinfo(curl, CURLINFO_PRIVATE, pointer); if(result ! CURLE_OK) printf(error: %s\n, curl_easy_strerror(result)); curl_easy_cleanup(curl); } }实际使用中void *pointer通常指向你自己定义的应用结构体。CURLOPT_PRIVATE 手册页 中的示例更典型地展示了这种用法——把整个struct private_data的地址存入 handle之后再用CURLINFO_PRIVATE提取回struct private_data *extracted。真实仓库用例multi 爬虫中的 per-handle 上下文仓库自带示例 docs/examples/crawler.c 展示了这个选项最典型的实战场景在并发传输中把 handle 与它的业务数据绑定。爬虫为每个页面创建独立 handle并让私有指针指向该页面专属的struct memory传输完成后在curl_multi_info_read的消息循环里凭CURLMSG_DONE拿到easy_handle再一次性恢复出对应的内存缓冲while((m curl_multi_info_read(multi, msgs_left))) { if(m-msg CURLMSG_DONE) { CURL *curl m-easy_handle; struct memory *mem; curl_easy_getinfo(curl, CURLINFO_PRIVATE, mem); /* ... 用 mem 解析该页面内容、统计大小、决定是否继续抓链接 ... */ } }见 docs/examples/crawler.c#L219-L236。这个模式成立的关键在于回调CURLOPT_WRITEFUNCTION等只收到void *userdata而 multi 完成通知里只有CURL *CURLINFO_PRIVATE正是从“仅凭 handle”恢复到“业务上下文”的桥梁。仓库中 docs/examples/multi-event.c、docs/examples/ghiper.c、docs/examples/hiperfifo.c、docs/examples/10-at-a-time.c 等并发示例也普遍采用CURLINFO_PRIVATE来关联 handle 与上层数据结构。典型使用场景归纳回调内定位上下文libcurl 的进度、下载、头部等回调参数中没有 handle但userdata通常就是 easy handle 本身如curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, cb)配合默认 userdata。在回调里先curl_easy_getinfo(userptr, CURLINFO_PRIVATE, ctx)即可拿到请求级配置、输出文件名、数据库会话等任意自定义数据。multi 事件循环如上例curl_multi_info_read只给出easy_handle需要反查该请求对应的业务对象。把 libcurl 嵌入框架当你不控制 handle 的创建时机例如由对象池统一创建可用私有指针在“框架层”与“libcurl 层”之间传递关联键。注意事项与边界行为类型转换方向设置时传void *取回时得到char *。C 中应显式转回原类型如struct ctx *ctx (struct ctx *)p;不要依赖隐式转换绕过编译器告警。libcurl 不负责生命周期libcurl 不拷贝、不释放该指针指向的内存。你必须保证私有数据在 handle 使用期间有效并在curl_easy_cleanup前自行释放handle 销毁不会替你 free 它。默认值为 NULL从未设置CURLOPT_PRIVATE的 handle取回结果为NULL可用于“该 handle 未关联上下文”的判断。内部 handle 不继承私有数据以 DoHDNS over HTTPS为例lib/vdns/doh.c#L379-L383 中有一段注释和断言/* DoH handles must not inherit private_data. The handles may be passed to the application ... private_data via CURLOPT_PRIVATE if they so choose. */ DEBUGASSERT(!doh-set.private_data);即 libcurl 内部为 DoH 解析另建的 handle 不会携带你设置的私有指针避免内部 handle 与应用 handle 的上下文混淆。线程安全前提CURLINFO_PRIVATE读取的是Curl_easy设置区的当前值遵循 libcurl 一贯的规则——对同一个 easy handle 的访问应保持串行不在一个线程调用 perform 的同时于另一线程调用 getinfo。返回值curl_easy_getinfo(3)返回一个CURLcode表示成功或失败CURLE_OK0表示一切正常非零表示发生错误错误码含义参见 libcurl-errors(3)。对于CURLINFO_PRIVATE这一取值分支而言正常路径下几乎总是返回CURLE_OK典型报错来自传入的handle或参数不合法。小结CURLINFO_PRIVATE是 libcurl 提供给应用层的一个“挂钩”通过CURLOPT_PRIVATE存入任意void *随时可用curl_easy_getinfo原样取回libcurl 全程不触碰其内容存储点见 lib/urldata.h#L908取回点见 lib/getinfo.c#L121-L123。它是回调上下文恢复和 multi 并发编程中 handle 与业务数据绑定的标准手段自 libcurl 7.10.3 起可用对所有协议生效。配套的 CURLOPT_PRIVATE 与 curl_easy_getinfo(3) 手册页以及仓库中 docs/examples/crawler.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),仅供参考
返回列表