ARTICLE DETAIL

资讯详情

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

libcurl 共享数据机制深度解析:CURLSHOPT_SHARE 选项与多句柄数据复用实战

libcurl 共享数据机制深度解析:CURLSHOPT_SHARE 选项与多句柄数据复用实战 libcurl 共享数据机制深度解析CURLSHOPT_SHARE 选项与多句柄数据复用实战【免费下载链接】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导读在多句柄easy handle并发访问同一批服务器资源时每个句柄各自维护 DNS 缓存、Cookie 会话、SSL 会话和连接池会造成明显的重复开销。libcurl 的 CURLSHOPT_SHARE 选项正是为解决这一问题而设计它通过 curl_share_init 创建的共享对象share object让多个 easy handle 之间共享 DNS 缓存、Cookie、SSL 会话、连接缓存、Public Suffix List 与 HSTS 缓存。本文以 docs/libcurl/opts/CURLSHOPT_SHARE.md 为主线结合仓库源码系统讲解该选项的用法、六种可共享数据类型的行为差异、线程安全要求及完整示例。CURLSHOPT_SHARE 是什么CURLSHOPT_SHARE 是 libcurl 中用于向共享对象添加share某类数据的选项通过 curl_share_setopt 接口调用#include curl/curl.h CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_SHARE, int type);type参数指定要共享的具体数据种类必须是下文列出的CURL_LOCK_DATA_*枚举值之一。你可以多次调用 CURLSHOPT_SHARE 并传入不同的 type让同一个共享对象同时共享多种数据若要取消共享某类数据则使用 CURLSHOPT_UNSHARE。该选项自 libcurl 7.10.3 加入适用于所有协议Protocol: All。使用前提先创建共享对象CURLSHOPT_SHARE 的share参数必须来自 curl_share_init 的返回值。从源码 lib/curl_share.c 可以看到share 对象内部会初始化引用计数share-ref_count 1、DNS 缓存Curl_dnscache_init(share-dnscache, 23)以及一个内部 admin easy handleshare-admin curl_easy_init()并记录specifier位掩码标识当前共享了哪些数据类型。关键使用时机不要在共享对象使用中修改Do not add types to a shared object that is being in use. Add them only between transfers.即不要向正在使用中的共享对象添加共享类型只能在两次传输之间添加。这一约束在源码中有强制校验lib/curl_share.c 中curl_share_setopt首先调用share_in_use(share)若已有 easy handle 引用该 shareref_count 1则直接返回CURLSHE_IN_USEif(share_in_use(share)) { /* do not allow setting options while one or more handles are already using this share */ return CURLSHE_IN_USE; }多线程使用必须设置锁回调如果共享的数据要被多个线程同时使用还必须同时设置互斥回调CURLSHOPT_LOCKFUNC获取锁时回调见 CURLSHOPT_LOCKFUNCCURLSHOPT_UNLOCKFUNC释放锁时回调锁回调的原型定义在 include/curl/curl.h锁数据的枚举curl_lock_datainclude/curl/curl.h中CURL_LOCK_DATA_SHARE专门用于表示修改共享对象内部状态的锁其余值对应各可共享数据类型。六种可共享的数据类型CURL_LOCK_DATA_COOKIE共享 Cookie 数据Cookie 数据在使用了该共享对象的多个 easy handle 之间共享。不激活 Cookie 处理共享 Cookie 并不会自动开启句柄的 Cookie 功能仍需单独通过 CURLOPT_COOKIEFILE 等选项激活不支持多线程并发共享 Cookie源码中启用该类型时lib/curl_share.c若当前构建未禁用 HTTP/CookieCURL_DISABLE_HTTP || CURL_DISABLE_COOKIES会调用Curl_cookie_init()初始化共享 Cookie 仓库否则返回CURLSHE_NOT_BUILT_IN。当 easy handle 绑定到该 share 时Curl_share_easy_link见 lib/curl_share.c句柄的data-cookies会指向共享 Cookie 仓库实现真正的一处更新、处处可见。CURL_LOCK_DATA_DNS共享 DNS 解析缓存缓存的 DNS 主机解析结果在使用了该共享对象的多个 easy handle 之间共享避免重复解析同一域名。重要前提当使用 multi 接口时加入同一个 multi handle 的所有 easy handle默认就共享 DNS 缓存无需设置本选项只有 easy 接口单句柄逐次 perform场景下该共享才有意义。CURL_LOCK_DATA_SSL_SESSION共享 SSL 会话缓存SSL 会话在多个 easy handle 之间共享能显著减少重连同一服务器时的 SSL 握手时间。multi 接口下同一 multi handle 内的 easy handle 默认共享 SSL 会话缓存无需设置源码中启用该类型时lib/curl_share.c调用Curl_ssl_scache_create(25, 2, ...)创建会话缓存。注释明确指出当前应用暂时无法配置共享会话缓存的大小且该缓存未针对数百个 peer 的场景做优化因此大小被刻意保持在合理水平25 个条目、2 路分片大量不同服务器的场景需谨慎使用。CURL_LOCK_DATA_CONNECT共享连接缓存将连接缓存放入共享对象使所有使用该 share 的 easy handle 共享连接池从而复用已建立的 TCP/TLS 连接。多线程限制与多路复用约束重点不支持多线程并发共享连接HTTP/2 与 HTTP/3 多路复用共享连接上只会附加由同一个 multi 或 easy handle 持有的现有连接的额外传输libcurl不支持在不同线程中通过共享连接做多路复用流multi 接口下同一 multi handle 内默认共享连接缓存无需设置连接数限制交互CURLMOPT_MAX_HOST_CONNECTIONS 与 CURLMOPT_MAX_TOTAL_CONNECTIONS 同样作用于使用共享连接缓存的传输——每个传输都会以它所在 multi handle 的限制为准对共享缓存生效。源码中启用该类型时lib/curl_share.c调用Curl_cpool_init(share-cpool, share, 103)初始化共享连接池销毁 share 时share_destroy也会随之Curl_cpool_destroy清理。CURL_LOCK_DATA_PSL共享 Public Suffix List7.61.0 加入共享对象中保存的 PSL公共后缀列表如.com、.co.uk这类公共后缀对所有绑定的 easy handle 可用。由于 PSL 会周期性刷新共享可以避免在过多不同上下文中重复更新。7.61.0 加入multi 接口下默认共享无需设置该类型依赖 libpsl 构建USE_LIBPSL未启用时返回CURLSHE_NOT_BUILT_IN。CURL_LOCK_DATA_HSTS共享内存中的 HSTS 缓存7.88.0 加入共享内存中的 HSTSHTTP Strict Transport Security缓存。7.88.0 加入不支持多线程并发共享 HSTS源码中启用时lib/curl_share.c调用Curl_hsts_init()初始化绑定时句柄的data-hsts指向共享缓存lib/curl_share.c。若构建时禁用了 HSTSCURL_DISABLE_HSTS同样返回CURLSHE_NOT_BUILT_IN。完整代码示例将上述共享类型落地到一段可运行的 C 代码#include stdio.h #include curl/curl.h int main(void) { CURLSHcode sh; CURLSH *share curl_share_init(); /* 一次调用共享一种数据类型可多次调用组合 */ sh curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); if(sh) printf(Error: %s\n, curl_share_strerror(sh)); sh curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); if(sh) printf(Error: %s\n, curl_share_strerror(sh)); sh curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); if(sh) printf(Error: %s\n, curl_share_strerror(sh)); /* ... 将 share 通过 CURLOPT_SHARE 绑定到各 easy handle ... */ curl_share_cleanup(share); return 0; }对应地取消某类数据共享使用 CURLSHOPT_UNSHARE见 CURLSHOPT_UNSHAREsh curl_share_setopt(share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE); if(sh) printf(Error: %s\n, curl_share_strerror(sh));同样地只能在两次传输之间共享对象未被句柄使用取消共享类型。绑定共享对象CURLOPT_SHARE共享对象最终要通过 CURLOPT_SHARE 绑定到具体 easy handle 上见 CURLOPT_SHAREcurl_easy_setopt(curl, CURLOPT_SHARE, shobject);绑定后该句柄对share 中已声明共享的数据使用共享副本而 share 未声明的数据仍按普通方式各自维护。典型的完整会话两个句柄共享 Cookie流程curl_share_init()创建共享对象curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE)声明共享 Cookie两个句柄分别curl_easy_setopt(CURLOPT_SHARE, share)绑定每个句柄用CURLOPT_COOKIEFILE, 激活各自共享同一仓库的Cookie 处理依次 perform第二个句柄即可继承第一个句柄积累的 Cookie全部结束后curl_share_cleanup(share)。将 CURLOPT_SHARE 重新设为 NULL 可解除绑定但在传输进行中设置/清除 share 是不鼓励的可能导致未定义行为文档明确警告见 CURLOPT_SHARE。返回值与错误处理CURLSHE_OK0表示选项设置成功非零表示出错。完整错误码列表include/curl/curl.h包括错误码含义CURLSHE_OK一切正常0CURLSHE_BAD_OPTION选项或 type 非法如传入未定义的数据类型CURLSHE_IN_USE共享对象正被句柄使用不能修改共享设置CURLSHE_INVALIDshare 句柄非法/已被清理CURLSHE_NOMEM内存不足CURLSHE_NOT_BUILT_IN目标特性未编译进 libcurl如未启用 SSL、libpsl、HSTS、Cookie 支持源码中curl_share_setopt的 switch 逻辑lib/curl_share.c与之一一对应未知 type 返回CURLSHE_BAD_OPTION被禁用的特性返回CURLSHE_NOT_BUILT_IN分配失败返回CURLSHE_NOMEM。详细错误说明可参考 libcurl-errors(3)。实践建议与注意事项汇总先声明再绑定在将 share 绑定到任何 easy handle 之前完成所有 CURLSHOPT_SHARE 声明之后只在两次传输之间调整共享类型否则会收到 CURLSHE_IN_USE。多线程必配锁只要共享数据会被多个线程并发使用就必须同时设置 CURLSHOPT_LOCKFUNC 与 CURLSHOPT_UNLOCKFUNC其中 Cookie、连接、HSTS 三类数据在文档层面明确不支持多线程并发共享即使配了锁也不建议跨线程共享。multi 接口的默认共享同一 multi handle 内的 easy handle 默认共享 DNS 缓存、SSL 会话缓存、连接缓存与 PSLCURLSHOPT_SHARE 主要用于 easy 接口场景或跨多个 multi handle 的共享。共享连接缓存与多路复用HTTP/2、HTTP/3 的多路复用流只能在同一 multi/easy handle 持有的连接上追加跨线程共享连接做多路复用不被支持共享连接缓存时CURLMOPT_MAX_HOST_CONNECTIONS / CURLMOPT_MAX_TOTAL_CONNECTIONS 仍按传输所在 multi handle 的限制对共享缓存生效。SSL 会话缓存规模共享 SSL 会话缓存的大小当前不可由应用配置且未针对大量 peer 优化涉及成百上千不同服务器时应评估其收益。Cookie 需要单独激活共享 Cookie 不等于启用 Cookie 处理仍需每个句柄通过 CURLOPT_COOKIEFILE 等选项显式开启。编译期依赖PSL 需要 libpslUSE_LIBPSLHSTS、Cookie 与 SSL 会话共享分别受 CURL_DISABLE_HSTS、CURL_DISABLE_HTTP/CURL_DISABLE_COOKIES、USE_SSL 等构建开关影响未启用时调用会得到 CURLSHE_NOT_BUILT_IN。掌握以上要点后你可以在自己的多句柄/多线程 libcurl 应用中安全地通过 CURLSHOPT_SHARE 复用 DNS、Cookie、SSL 会话与连接显著减少重复握手与重复解析带来的开销。【免费下载链接】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),仅供参考
返回列表