libcurl CURLOPT_STREAM_DEPENDS 详解:HTTP/2 流依赖设置、使用条件与弃用演进
发布时间:2026/9/10 13:52:18 作者:尧图编辑部 阅读量:1,286

libcurl CURLOPT_STREAM_DEPENDS 详解HTTP/2 流依赖设置、使用条件与弃用演进【免费下载链接】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 开源仓库中 CURLOPT_STREAM_DEPENDS.md 官方文档为核心系统讲解 libcurl 中 HTTP/2 流依赖stream dependency选项的 API 用法、语义约束、底层实现与弃用背景。读完本文你将掌握如何在同一个 HTTP/2 连接上为多个 easy handle 声明流间依赖关系、它与独占依赖及流权重选项的配合方式以及为什么从 8.21.0 起该选项已不再生效并能在升级代码时做出正确的取舍。一、选项概述声明这个传输依赖那个传输CURLOPT_STREAM_DEPENDS用于告诉 libcurl当前 easy handle 发起的 HTTP/2 流依赖同一个连接上的另一个流。设置后libcurl 会在与服务器协商 HTTP/2 优先级树时表达这种依赖关系从而影响服务器端对多个并发流的资源分配。其对应的规范语义是见原文档引述Including a dependency expresses a preference to allocate resources to the identified stream rather than to the dependent stream.即声明依赖本质上是表达把资源优先分配给被依赖的流identified stream而不是依赖方dependent stream的偏好。依赖方会获得较少的资源份额被依赖方会优先获得带宽与调度机会。适用协议HTTP仅 HTTP/2 场景下有意义引入版本7.46.0默认值NULL不设置任何依赖当前状态自 8.21.0 起已弃用设置后不再有任何效果二、API 签名与参数说明#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_DEPENDS, CURL *dephandle);参数类型含义handleCURL *当前要设置依赖关系的 easy handle即依赖方dephandleCURL *被依赖的另一个 easy handle即被依赖方parent stream使用该选项需注意以下几点dephandle不能与handle是同一个句柄。如果两者相同curl_easy_setopt会返回错误。必须是另一个 easy handle不能是NULL或与自身重复。两个句柄必须走同一个 HTTP/2 连接。只有当dephandle所属的传输即将通过同一条 HTTP/2 连接发送时该选项才具有实际效果如果两个传输被分配到不同连接依赖声明不会生效。可以在传输进行中during transfer动态设置无需在开始传输前一次性配置完毕。与独占依赖选项互斥CURLOPT_STREAM_DEPENDS与 CURLOPT_STREAM_DEPENDS_E_E即 Exclusive是互斥的设置CURLOPT_STREAM_DEPENDS会清除独占位exclusive bit设置CURLOPT_STREAM_DEPENDS_E则会置位独占标志。在 HTTP/2 优先级树中独占依赖意味着当某个流被重新指定为另一个流的独占子节点时原父节点的所有其他子依赖会全部转移为该新流的子节点。普通非独占依赖则只是简单地把新流挂到被依赖流之下作为其众多子节点之一。三、完整可运行示例原文档给出了最小示例骨架这里补全为可直接编译运行、并加入多句柄调度与错误检查的完整版本#include stdio.h #include curl/curl.h int main(void) { CURL *curl curl_easy_init(); CURL *curl2 curl_easy_init(); /* 第二个句柄依赖方 */ CURLM *multi curl_multi_init(); CURLcode res; if(!curl || !curl2 || !multi) { fprintf(stderr, 初始化失败\n); return 1; } /* 第一个句柄被依赖的流 */ curl_easy_setopt(curl, CURLOPT_URL, https://example.com/one); /* 第二个句柄声明依赖第一个句柄的流 */ curl_easy_setopt(curl2, CURLOPT_URL, https://example.com/two); res curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS, curl); if(res ! CURLE_OK) { fprintf(stderr, 设置 CURLOPT_STREAM_DEPENDS 失败: %d\n, res); return 1; } /* 将两个句柄加入 multi handle 并发传输 */ curl_multi_add_handle(multi, curl); curl_multi_add_handle(multi, curl2); /* 驱动 multi 接口直到所有传输完成此处省略完整的 curl_multi_poll/perfom 轮询循环 */ curl_multi_remove_handle(multi, curl2); curl_multi_remove_handle(multi, curl); curl_multi_cleanup(multi); curl_easy_cleanup(curl2); curl_easy_cleanup(curl); return 0; }要点回顾CURLOPT_STREAM_DEPENDS设置在依赖方curl2上参数传入被依赖方curl两个 URL 必须最终复用同一条HTTP/2 连接依赖才有实际意义实际调度由 multi 接口驱动同时挂载两个句柄并发传输。四、配套选项独占依赖与流权重流优先级体系由三个选项共同构成理解它们才能完整把握 HTTP/2 优先级调度的全貌。CURLOPT_STREAM_DEPENDS_E独占依赖CURLOPT_STREAM_DEPENDS_E 与CURLOPT_STREAM_DEPENDS参数形式完全一致CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_DEPENDS_E, CURL *dephandle);区别仅在语义上它声明的是独占依赖会设置 HTTP/2 优先级规格中的 Exclusive 位。独占依赖会让被重新指定优先级的流成为新父节点后把原父节点下的所有其他依赖一并收编为自己的子节点从而在优先级树中占据更明确的调度位置。与原选项相同它也要求dephandle是另一个、且属于同一 HTTP/2 连接的 easy handle并同样自 8.21.0 起弃用。CURLOPT_STREAM_WEIGHT流权重CURLOPT_STREAM_WEIGHT 用于设置流的数值权重与依赖共同描述优先级树中的资源分配比例CURLcode curl_easy_setopt(CURL *handle, CURLOPT_STREAM_WEIGHT, long weight);weight取值范围1 到 256默认值16这也是 HTTP/2 规范中的默认权重同一父节点下的多个流按权重成比例分配资源。例如流 A 权重 16、流 B 权重 32则 B 获得可用带宽的 32/(1632)2/3假定服务器对两个流都能同等速率发送该选项同样可以在传输进行中设置更新后的权重会在下一次向服务器发送 HTTP/2 帧时生效。依赖决定优先级树的结构谁是谁的父节点权重决定同一父节点下的兄弟流之间如何按比例分配资源二者配合即构成 RFC 7540 的优先级模型。五、源码实现印证选项如何被处理选项登记与类型在 lib/easyoptions.c 中三个相关选项登记如下{ STREAM_DEPENDS, CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0 }, { STREAM_DEPENDS_E, CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0 }, { STREAM_WEIGHT, CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0 },STREAM_DEPENDS与STREAM_DEPENDS_E被声明为CURLOT_OBJECT类型即它们的取值是一个对象指针这里即CURL *句柄而非数值或字符串。8.21.0 之后的实际行为在 lib/setopt.c 中可以看到当前版本的实现case CURLOPT_STREAM_DEPENDS: /* CURL * */ case CURLOPT_STREAM_DEPENDS_E: /* CURL * */ return CURLE_OK;两个 case 直接落入return CURLE_OK——也就是说设置该选项永远返回成功但不再执行任何实际的依赖登记动作。这正是原文档Since version 8.21.0 setting this option no longer has an effect自 8.21.0 起设置该选项不再有效在源码层面的直接体现调用方不会收到错误但依赖关系不会再被提交给 HTTP/2 栈。权重与优先级帧的底层通路历史实现参考虽然依赖选项已失效但流权重相关的底层逻辑仍可帮助我们理解这套机制当年是如何落地的。在 lib/http2.c 中sweight_wanted()/sweight_in_effect()读取data-set.weight用户设置值与data-state.weight当前生效值用户未设置时回退到NGHTTP2_DEFAULT_WEIGHTh2_pri_spec()填充nghttp2_priority_spec结构调用nghttp2_priority_spec_init(pri_spec, 0, sweight_wanted(data), FALSE)——第三个参数是权重第四个参数是 exclusive 位h2_progress_egress()检测到权重/依赖发生变化时通过nghttp2_submit_priority()向服务器提交 HTTP/2PRIORITY帧并立即尝试nghttp2_session_send()刷出。从这段实现可以推断早期的优先级机制正是通过 nghttp2 的 priority spec 与 PRIORITY 帧将依赖树和权重同步给对端如今依赖部分被移除后这部分通路仅剩权重逻辑仍在运转。六、弃用背景RFC 7540 → RFC 9113流依赖与权重是 HTTP/2 优先级调度的核心概念但它们的命运经历了两次转折引入RFC 7540HTTP/2首次定义了流优先级机制包括依赖dependency与权重weight本节参考其第 5.3 节弃用后续的 RFC 9113HTTP/2 修订版正式弃用了流依赖。实践中服务器与中间件对优先级信号的实现参差不齐、甚至普遍忽略导致该机制的实际收益远低于设计预期。因此 curl 从 8.21.0 起CURLOPT_STREAM_DEPENDS与CURLOPT_STREAM_DEPENDS_E均标记为Deprecated设置它们不再有任何效果源码层面仅返回CURLE_OK空操作流权重CURLOPT_STREAM_WEIGHT仍保留但同样建立在被 RFC 9113 调整过的优先级模型之上。对使用者的建议若代码中仍在调用这两个依赖选项可以安全移除——它们不会报错但也确实什么都不做对传输调度有强需求的场景应关注服务器端实际支持的优先级策略如 HTTP/2 流调度、HTTP/3 扩展优先级等而不是依赖已被规范弃用的流依赖信号。七、返回值与错误处理curl_easy_setopt()对任何选项统一返回CURLcodeCURLE_OK0设置成功非零发生错误具体含义参见 libcurl 错误码文档。就CURLOPT_STREAM_DEPENDS而言需要注意的特殊错误场景是当dephandle与handle为同一个句柄时函数返回错误。当前版本≥8.21.0下该选项恒返回CURLE_OK因此调用方不应依赖返回值判断依赖是否真正建立。八、小结CURLOPT_STREAM_DEPENDS7.46.0 引入用于在同一个 HTTP/2 连接内声明本流依赖另一个流配合独占依赖CURLOPT_STREAM_DEPENDS_E与流权重CURLOPT_STREAM_WEIGHT构成完整的 HTTP/2 优先级控制面它要求被依赖方是另一个 easy handle、两者必须复用同一 HTTP/2 连接且允许在传输中动态设置由于 RFC 9113 弃用了流依赖机制curl 自 8.21.0 起将该选项标记为废弃设置后仅返回CURLE_OK而不再产生实际效果见 lib/setopt.c升级到新版本时删除依赖相关代码即可无需保留兼容逻辑。参考文档与源码CURLOPT_STREAM_DEPENDS.md、CURLOPT_STREAM_DEPENDS_E.md、CURLOPT_STREAM_WEIGHT.md、lib/setopt.c、lib/http2.c、lib/easyoptions.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),仅供参考