有没有什么情况会导致curl_multi_perform被阻塞? 我正在使用curl_multi接口构建https服务,但我们发现curl_multi_perform接口在弱网络条件下会阻塞。 接口内部是否有非异步的调用?造成堵塞。
我想知道一些原因。
是的,在某些条件下
curl_multi_perform
可以阻止,特别是在弱网络条件下。以下是一些可能的原因:
DNS解析:如果DNS解析时间较长,可能会导致阻塞。默认情况下,cURL 执行同步 DNS 解析,如果 DNS 查找速度慢,可能会阻塞整个过程。您可以通过使用带有异步 DNS 解析的 cURL 来缓解此问题,例如
c-ares
或类似的。
SSL/TLS 握手:SSL/TLS 握手过程是通过 HTTPS 建立安全连接所必需的,但可能非常耗时,尤其是在网络连接较弱的情况下。如果花费太长时间,此过程可能会阻塞。
网络超时和重试:在弱网络条件下,数据包丢失和高延迟可能会导致重复重试和延长超时,这可能会导致
curl_multi_perform
出现阻塞。
阻塞回调:如果使用 cURL 注册的任何回调(如
write
、read
或 progress
回调)本身执行阻塞操作,它们可能会导致 curl_multi_perform
阻塞。
套接字操作:虽然
curl_multi_perform
设计为非阻塞,但底层套接字操作在某些情况下可能会阻塞,特别是在操作系统的网络堆栈或服务器没有响应的情况下。
要解决这些问题,您可以:
使用异步 DNS:使用
c-ares
启用异步 DNS。这可以通过构建具有 c-ares
支持的 cURL 并使用适当的 cURL 选项来启用它来完成。
调整超时:使用
CURLOPT_TIMEOUT
、CURLOPT_CONNECTTIMEOUT
和 CURLOPT_DNS_SERVERS
等选项为连接过程的各个阶段设置适当的超时。
使用非阻塞套接字:确保套接字设置为非阻塞模式。 cURL 通常会处理这个问题,但最好仔细检查一下。
监控和调试:使用详细模式 (
CURLOPT_VERBOSE
) 获取 cURL 正在执行的操作的详细日志。这可以帮助您查明阻塞发生的位置。
以下是如何设置其中一些选项的示例:
CURLM *multi_handle;
CURL *easy_handle;
multi_handle = curl_multi_init();
easy_handle = curl_easy_init();
curl_easy_setopt(easy_handle, CURLOPT_URL, "https://example.com");
curl_easy_setopt(easy_handle, CURLOPT_TIMEOUT, 30L);
curl_easy_setopt(easy_handle, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE, 1L);
curl_multi_add_handle(multi_handle, easy_handle);
int still_running;
do {
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
if (mc == CURLM_OK) {
int numfds;
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if (mc != CURLM_OK) {
fprintf(stderr, "curl_multi_wait() failed, code %d.\n", mc);
break;
}
if (!numfds) {
fprintf(stderr, "No file descriptors ready.\n");
usleep(100000); // Sleep for a bit to avoid busy-looping
}
} else {
fprintf(stderr, "curl_multi_perform() failed, code %d.\n", mc);
break;
}
} while (still_running);
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(easy_handle);
此示例为整个请求和连接阶段设置超时,并使用
curl_multi_wait
有效地等待文件描述符上的活动。调整这些参数可以帮助缓解弱网络条件下的阻塞问题。