(解决curl_easy_perform阻塞很久的问题)libcurl的share interface与curl_easy_perform的性能

文章讲述了在使用libcurl时遇到性能问题,通过分析发现每次新curlhandle都会启动DNS解析线程。解决办法是启用CURLOPT_DNS_USE_GLOBAL_CACHE或使用shareinterface,共享DNS缓存,从而提高HTTP连接性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在使用libcurl实现客户端程序和http server通讯功能的时候,发现libcurl的性能不好。

具体情况是我在每次http连接时初始化一个新的curl handle,参数设置完成后,调用curl_easy_perform方法执行本连接。 如果程序中需要用到http连接比较少,感觉不到异常。但在测试中发现,程序需要大量http连接的时候,curl_easy_perform的性能很差。

 

调查发现,在curl_easy_perform方法每次执行时,libcurl都会启动一个线程,执行结束后结束这个线程。经研究libcurl的源代码发现,libcurl在curl_easy_perform方法中启动的线程用于做DNS解析, libcurl对于每一个curl hanlle有一个DNS cache,默认超时时间为60秒,如果不重用curl handle的话,这个dns cache在连接完成后就被析构了。我的程序没有重用curl handle,所以每个连接都会去启动线程做DNS解析。

 

 

问题来了,在不重用curl handle的情况下,怎么保证DNS cache一直有效,各个不同的curl handle能共用这个DNS cache呢?答案是有的,有个CURLOPT_DNS_USE_GLOBAL_CACHE设置,可以让libcurl所有http连接都使用一个全局的DNS cache。但是在查阅libcurl文档的时候,看到下面一段话:

 

15.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE

Remove support for a global DNS cache. Anything global is silly, and we already offer the share interface for the same functionality but done "right". 

 

 

也就是CURLOPT_DNS_USE_GLOBAL_CACHE将会在以后版本被去除掉,原因是设置CURLOPT_DNS_USE_GLOBAL_CACHE后虽然能够使用全局DNS cache,但任何全局的东西都是愚蠢的,而且libcurl已经提供了share interface可以用恰当的方式做同样的事。

 

在使用share interface的curl_share_init初始化share handle以后,使用curl_share_setopt设置共享对象,目前可以支持cookie和dns,在每一个curl handle执行前,使用CURLOPT_SHARE选项把这个share handle设置给curl handle,这样多个curl handle就可以共用同一个DNS cache了,代码如下:

[c-sharp:nogutter:firstline[1]] view plaincopy
  1. void set_share_handle(CURL* curl_handle)  
  2. {  
  3.     static CURLSH* share_handle = NULL;  
  4.     if (!share_handle)  
  5.     {  
  6.         share_handle = curl_share_init();  
  7.         curl_share_setopt(share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);  
  8.     }  
  9.     curl_easy_setopt(curl_handle, CURLOPT_SHARE, share_handle);  
  10.     curl_easy_setopt(curl_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5);  
  11. }  

 将上面的这段代码放进curl的设置当中,当没有连接外网的时候调用curl_easy_perform就不会阻塞太久,不超过一秒,如果没有加的话,会阻塞20-50s的时间,很操蛋!总之加上上面的就好了!

注意,默认的DNS cache的超时时间为60秒,如果想把超时设得大一些,可以使用CURLOPT_DNS_CACHE_TIMEOUT选项来设置,如上将超时时间设为5分钟。

 

用share interface的话,我们在程序中可以灵活配置具体哪些http连接使用哪些DNS cache。在超时时间内,每次curl_easy_perform执行时不会再启动解析DNS的线程了,效率大大提高。

 

实践证明,不是libcurl的性能不好,而是我沒有用好它。:)

<think>好的,用户想了解curl_easy_perform函数的返回值含义和可能的错误情况。首先,我需要回忆一下libcurl的相关知识。curl_easy_performlibcurl中执行输的核心函数,返回值为CURLcode类型,每个值代表不同的状态或错误。 我应该先整理常见的错误码,比如CURLE_OK表示成功,而其他如CURLE_COULDNT_CONNECT、CURLE_OPERATION_TIMEDOUT等需要解释。用户提到的引用中有关于SSL错误的例子,比如CURLOPT_SSL_VERIFYHOST和CURLOPT_SSL_VERIFYPEER的设置,这可能涉及CURLE_SSL_CONNECT_ERROR或CURLE_PEER_FAILED_VERIFICATION等错误码。 另外,引用[4]提到系统时间不正确导致证书问题,这可能对应CURLE_SSL_CACERT或类似的错误。需要将错误码和可能的原因对应起来,比如问题、SSL配置、超时、资源问题等。 还要注意用户可能遇到的典型错误场景,并提供解决方法。例如,返回60(CURLE_SSL_CACERT)时,检查CA证书路径或系统时间是否正确。同时,提醒用户不要在生产环境中禁用SSL验证,引用中的例子虽然解决问题,但存在安全隐患。 需要确保覆盖主要的错误码,并分类说明,比如连接问题、SSL/TLS错误、协议错误等。最后,生成相关问题,帮助用户进一步学习,如错误处理的最佳实践或SSL验证的详细配置。</think>### curl_easy_perform函数返回值详解 #### 一、返回值基本含义 `curl_easy_perform`函数的返回值类型为`CURLcode`,用于表示HTTP请求执行状态: - **0(CURLE_OK)**:操作成功完成 - **非零值**:表示具体错误类型,可通过`curl_easy_strerror()`转换为可读错误信息 #### 二、常见错误码分类解析 1. **连接类错误**: - **7(CURLE_COULDNT_CONNECT)**:无法建立TCP连接,检查目标地址/端口或防火墙设置[^2] - **28(CURLE_OPERATION_TIMEDOUT)**:操作超时,可通过`CURLOPT_TIMEOUT`调整超时时间 - **6(CURLE_COULDNT_RESOLVE_HOST)**:DNS解析失败,检查域名有效性或DNS配置 2. **SSL/TLS错误**: - **60(CURLE_SSL_CACERT)**:SSL证书验证失败(常见CA证书问题),参考[^1][^4] - **35(CURLE_SSL_CONNECT_ERROR)**:SSL握手失败,可能协议版本不兼容 - **51(CURLE_PEER_FAILED_VERIFICATION)**:对端证书验证失败 3. **协议错误**: - **22(CURLE_HTTP_RETURNED_ERROR)**:HTTP响应码>=400,可通过`CURLOPT_FAILONERROR`控制 - **55(CURLE_SEND_ERROR)**:发送数据失败,检查络连接或发送缓冲区 4. **资源相关错误**: - **23(CURLE_WRITE_ERROR)**:写入回调函数返回错误 - **27(CURLE_OUT_OF_MEMORY)**:内存分配失败 #### 三、错误处理建议 ```c CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "请求失败: %s\n", curl_easy_strerror(res)); // 特定错误处理 if(res == CURLE_SSL_CACERT) { // 检查CA证书路径或系统时间 } } ``` #### 四、调试技巧 1. 启用详细日志: ```c curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); ``` 2. SSL验证临时禁用(仅限调试): ```c curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值