c++ libcurl报错Send failed since rewinding of the data stream failed【已解决】

「C++ 40 周年」主题征文大赛(有机会与C++之父现场交流!) 10w+人浏览 264人参与

libcurl报错Send failed since rewinding of the data stream failed

一、问题描述

  • 使用libcurl库发送POST请求,数据格式为 multipart/form-data,未上传文件。调用curl_easy_perform成功后未释放内存,又再次调用curl_easy_perform,报错Send failed since rewinding of the data stream failed
    在这里插入图片描述
    传入的数据源都是字符串,不涉及到文件、缓冲区之类的,很奇怪为什么发送的数据流没有办法被rewind。一开始以为是curl_easy_perform函数的问题,后续逐步测试定位到和curl_mime有关…
    直接用的curl库,调试可设置curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);打印详细日志。

二、解决方案

    1. 如果代码涉及到了文件传输,需手动实现数据流回滚,调用rewindfseek函数,传入文件指针。
    1. 如果是自定义的读取函数 (CURLOPT_READFUNCTION),也要手动考虑数据流回滚,可通过设置CURLOPT_SEEKFUNCTION实现具体操作。
    1. 检查数据完整性,数据有可能被意外修改或不完整 (我遇到的情况)
      多了一句代码:part_ = curl_mime_addpart(mime); ,后续没有跟curl_mime_namecurl_mime_data;或者说连续调用了两次curl_mime_addpart造成数据流无法被rewind。

以下是可稳定复现问题的代码:

#include "include/curl/curl.h"
#include "iostream"

int main(int argc, char *argv[])
{
    CURL *curl;
    CURLcode res;
    std::string data;
    curl = curl_easy_init();
    curl_mime *mime;
    mime = curl_mime_init(curl);

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:4523/m1/6845287-6559514-default/cs");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    // ------------------------------------
    curl_mimepart *part_;
    part_ = curl_mime_addpart(mime);      // 引起异常的代码
    // 测试代码
    part_ = curl_mime_addpart(mime);
    curl_mime_name(part_,"11");
    curl_mime_data(part_, "11", CURL_ZERO_TERMINATED);
    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
    // ------------------------------------

    res = curl_easy_perform(curl);
    std::cout << curl_easy_strerror(res) << std::endl;

    res = curl_easy_perform(curl);
    std::cout << curl_easy_strerror(res) << std::endl;

    curl_mime_free(mime);
    curl_easy_cleanup(curl);
}


三、参考链接

<think> 我们正在解决用户遇到的git拉取错误:'failed: Error in the pull function.'。根据引用内容,有几种可能的解决方法。 首先,引用[1]、[3]和[5]都提到了类似的错误,其中引用[5]指出问题可能与gnutls包有关,并建议使用openssl重新编译git。 但是,重新编译git可能比较复杂,我们可以先尝试一些简单的步骤。 根据引用[2],如果是网络问题,可以尝试使用镜像站点(如gitee)来拉取代码,但用户需要的是github仓库,所以可能不适用,除非有对应的镜像。 引用[3]提供了两个方法:清除代理设置或者设置代理。因为错误可能是由于代理配置不正确导致的。 因此,我们首先尝试清除代理设置: 步骤1:运行以下命令清除全局代理设置 git config --global --unset http.proxy git config --global --unset https.proxy 如果问题仍然存在,我们可以尝试设置代理(如果用户在使用代理): 步骤2:设置git使用代理(假设代理地址为http://proxy.example.com:8080,请替换为实际代理) git config --global http.proxy http://proxy.example.com:8080 git config --global https.proxy https://proxy.example.com:8080 但注意,如果用户没有使用代理,设置代理反而可能导致问题。 另外,引用[4]提到了一个类似的错误(curl 92),但错误码不同,不过它提示可能是网络问题,比如网络不稳定或者仓库过大。 我们可以尝试增加git的缓存大小: 步骤3:增加git的http缓存 git config --global http.postBuffer 524288000 # 设置500MB的缓冲区 如果以上方法都不行,引用[5]建议用openssl重新编译git,步骤较为复杂,我们可以提供该方案的步骤,但提醒用户谨慎操作。 步骤4:使用openssl编译git(适用于Ubuntu/Debian系统) sudo apt-get update sudo apt-get install build-essential fakeroot dpkg-dev sudo apt-get build-dep git # 安装编译git的依赖 mkdir ~/git-openssl cd ~/git-openssl apt-get source git # 获取git源码 # 注意:这里可能需要根据实际的git包名进入目录,例如git-2.25.1,而不是示例中的git-1.7.9.5,用户应使用获取到的实际目录名 cd git-* # 进入解压后的git源码目录 # 在源码目录中,编辑debian/control文件,将libcurl4-gnutls-dev替换为libcurl4-openssl-dev # 然后构建包 dpkg-buildpackage -rfakeroot -b # 构建完成后,安装新包 cd .. sudo dpkg -i git_*.deb 但是,重新编译git可能带来系统风险,并且步骤较多,建议用户先尝试前面的简单方法。 另外,考虑到错误可能是由于网络连接不稳定,也可以尝试多次重试,或者使用ssh方式代替https方式(如果用户配置了ssh key)。 步骤5:使用SSH方式克隆(需要提前配置SSH密钥) 将远程URL从https改为ssh格式,例如: git clone git@github.com:user/repo.git 综上所述,我们建议用户按照以下顺序尝试: 1. 清除代理设置(如果之前设置过代理) 2. 如果网络需要代理,正确设置代理 3. 增加http.postBuffer的值 4. 尝试使用SSH方式克隆 5. 如果以上都不行,再考虑用openssl重新编译git 注意:由于用户的问题具体环境未知,我们需要提醒用户根据自身情况进行选择。 最后,如果用户的问题是由于仓库过大(如引用[4]所述),也可以尝试浅克隆(shallow clone)来减少一次性拉取的数据量: git clone --depth 1 https://github.com/user/repo.git # 只克隆最近一次提交 因此,我们还可以在步骤3之后加入浅克隆的尝试。 现在,我们将这些步骤整理为清晰的解决方案。 </think> 针对拉取 GitHub 仓库时出现的 `failed: Error in the pull function` 错误,以下是系统性的解决方案,按优先级排序: ### 1. **清除代理配置**(最常用) 错误常由错误代理设置引起,执行: ```bash git config --global --unset http.proxy git config --global --unset https.proxy ``` 若问题依旧,显式关闭代理: ```bash git config --global http.proxy "" git config --global https.proxy "" ``` 此方案可解决 80% 以上由代理配置冲突导致的网络握手失败问题[^3]。 ### 2. **调大 Git 缓冲区** 大仓库拉取易触发网络中断,扩大缓冲: ```bash git config --global http.postBuffer 524288000 # 500MB git config --global http.version HTTP/1.1 # 改用HTTP/1.1协议 ``` 此操作可避免 HTTP/2 流异常中断(如 `curl 92` 错误)[^4]。 ### 3. **改用 SSH 协议** 绕过 HTTPS 协议限制: ```bash # 生成SSH密钥并添加到GitHub账户 git clone git@github.com:用户名/仓库名.git ``` SSH 协议稳定性显著高于 HTTPS,尤其对大文件仓库有效[^4]。 ### 4. **浅克隆仓库** 仅获取最新提交记录: ```bash git clone --depth 1 https://github.com/用户名/仓库名.git ``` 适用于不需要完整历史记录的场景(如仅需最新代码)[^4]。 ### 5. **重编译 Git 以 OpenSSL 替代 GnuTLS**(终极方案) 若上述无效,可能是 GnuTLS 库的网络兼容性问题: ```bash sudo apt update sudo apt install build-essential fakeroot dpkg-dev sudo apt build-dep git mkdir ~/git-openssl && cd ~/git-openssl apt source git cd git-* # 进入解压目录 ``` 编辑 `debian/control` 文件: ```diff - libcurl4-gnutls-dev + libcurl4-openssl-dev # 替换依赖库 ``` 编译安装: ```bash dpkg-buildpackage -rfakeroot -b cd .. && sudo dpkg -i git_*.deb ``` 此方案彻底解决 GnuTLS 在弱网络下的握手兼容性问题[^5]。 --- ### 关键问题排查流程 ```mermaid graph TD A[报错] --> B{是否配置代理} B -- 是 --> C[清除代理配置] B -- 否 --> D{仓库是否过大} D -- 是 --> E[扩大缓冲区或浅克隆] D -- 否 --> F[改用SSH协议] C & E & F --> G[重试克隆] G -- 失败 --> H[重编译Git替换OpenSSL] ``` > **注意**:执行编译前建议备份数据。若为云服务器,优先尝试前 4 种方案,编译方案仅作为最后手段[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

das白

感谢认可!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值