Libcurl multi重试机制仅重试1次跳过后续请求问题如何解决
问题核心原因
失败请求的handle未重置重加,无法发起二次请求
当前逻辑仅将返回200的easy handle从multi实例中移除,失败的handle会一直留在multi实例中。libcurl中完成过一次请求的easy handle,除非先移除再重新添加、或重置状态,否则不会重复发起请求,第二次进入loop执行curl_multi_perform时会直接判定所有任务已完成,不会发起新的请求。二次执行无完成消息,rerun未被赋值导致重试中断
每次进入消息处理逻辑前,rerun都会被初始化为0。第二次执行时没有新的请求完成,curl_multi_info_read直接返回NULL,消息处理循环完全不执行,rerun保持0值,自然不会触发下一次重试。
修复方案
处理完成消息时无论成功失败,都先将对应easy handle从multi实例移除,维护失败请求列表,重试前重置失败handle的状态、重新设置请求参数,再加回multi实例即可。
参考修改后的核心代码逻辑:
CURL* array[] = { curl_easy_init(), curl_easy_init(), curl_easy_init() }; CURLM* multi = curl_multi_init(); // 提前存好所有请求的URL,方便重试时设置 const char* urls[] = { "https://www.example.com/", "https://www.example.com/", "https://americas.api.riotgames.com/riot/account/v1/accounts/by-puuid/Dxon1TsoGLOAvUykGYErrEPAT_U9YkQ_jNFZpRxYpfRFwnaYVFULVshNQnZapa4qR_pe5sSBn5MQvw" }; for (int i = 0; i < 3; i++) { curl_easy_setopt(array[i], CURLOPT_URL, urls[i]); curl_multi_add_handle(multi, array[i]); } int retry = 3; loop: int run = 1; while (run) { CURLMcode mc = curl_multi_perform(multi, &run); if (mc == CURLM_OK) { mc = curl_multi_poll(multi, NULL, 0, 0, NULL); } if (mc != CURLM_OK) { exit(0); } } CURLMsg *msg; long rerun = 0; int msgNum = 0; int failed[3] = {0}; // 标记失败的请求下标 while (msg = curl_multi_info_read(multi, &msgNum)) { if (msg->msg == CURLMSG_DONE) { if (msg->data.result != CURLE_OK) { puts("ERROR"); exit(0); } long httpCode; curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &httpCode); // 无论成功失败先移除handle curl_multi_remove_handle(multi, msg->easy_handle); if (httpCode == 200) { // 成功请求直接处理响应即可 } else { rerun = httpCode; printf("\nError : %d\n", rerun); // 标记对应下标为失败 for (int i = 0; i < 3; i++) { if (array[i] == msg->easy_handle) { failed[i] = 1; break; } } } } else { puts("ERROR"); exit(0); } } puts("NExt"); if (rerun && --retry) { printf("%d - %d\n", retry, rerun); Sleep(1000); // 把失败的handle重置参数后重新加回multi for (int i = 0; i < 3; i++) { if (failed[i]) { curl_easy_reset(array[i]); curl_easy_setopt(array[i], CURLOPT_URL, urls[i]); // 其他需要设置的参数(比如header、超时等)也在这里重新设置 curl_multi_add_handle(multi, array[i]); } } goto loop; } // 最后统一清理handle和multi实例 for (int i = 0; i < 3; i++) { curl_easy_cleanup(array[i]); } curl_multi_cleanup(multi); puts("Finisheed"); exit(0);
额外说明:示例中返回的401是授权错误,说明请求缺少有效身份凭证,这类错误重试不会生效,仅服务端5xx错误、网络超时等场景重试才有意义。
内容的提问来源于stack exchange,提问作者LardPies
相关产品推荐
相关产品推荐

