关于使用libcurl的注意事项

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

调用libcurl下载,然后使用netstat查看发现有大量的TCP连接保持在CLOSE_WAIT状态
查看libcurl的文档说明,有这样一个选项:

CURLOPT_FORBID_REUSE

Pass a long. Set to 1 to make the next transfer explicitly close the connection when done. Normally, libcurl keeps all connections alive when done with one transfer in case a succeeding one follows that can re-use them. This option should be used with caution and only if you understand what it does. Set to 0 to have libcurl keep the connection open for possible later re-use (default behavior).

也就是说,默认情况下libcurl完成一个任务以后,出于重用连接的考虑不会马上关闭
如果没有新的TCP请求来重用这个连接,那么只能等到CLOSE_WAIT超时,这个时间默认在7200秒甚至更高,太多的CLOSE_WAIT连接会导致性能问题

解决方法:

curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
最好再修改一下TCP参数调低CLOSE_WAIT和TIME_WAIT的超时时间

libcurl 是一个很不错的库,支持http,ftp等很多的协议。使用库最大的心得就是,不仔细看文档,仅仅看着例子就写程序,是一件危险的事情。我的程序崩溃了,我怀疑是自己代码写的问题,后来发现是库没用对。不仔细看文档(有时候文档本身也比较差劲,这时除了看仔细外,还要多动脑子,考虑它是怎么实现的),后果很严重。不加思索的使用别人的库或者代码,有时候很惬意,但是出问题时,却是寝食难安的。

1 . CURLcode curl_global_init(long flags); 在多线程应用中,需要在主线程中调用这个函数。这个函数设置libcurl所需的环境。通常情况,如果不显式的调用它,第一次调用curl_easy_init()时,curl_easy_init 会调用 curl_global_init,在单线程环境下,这不是问题。但是多线程下就不行了,因为curl_global_init不是线程安全的。在多个线程中调用curl_easy_int,然后如果两个线程同时发现curl_global_init还没有被调用,同时调用curl_global_init,悲剧就发生了。这种情况发生的概率很小,但可能性是存在的。

2 . libcurl 有个很好的特性,它甚至可以控制域名解析的超时。但是在默认情况下,它是使用alarm + siglongjmp 实现的。用alarm在多线程下做超时,本身就几乎不可能。如果只是使用alarm,并不会导致程序崩溃,但是,再加上siglongjmp,就要命了(程序崩溃的很可怕,core中几乎看不出有用信息),因为其需要一个sigjmp_buf型的全局变量,多线程修改它。(通常情况下,可以每个线程一个 sigjmp_buf 型的变量,这种情况下,多线程中使用 siglongjmp 是没有问题的,但是libcurl只有一个全局变量,所有的线程都会用)。

具体是类似 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L) 的超时设置,导致alarm的使用(估计发生在域名解析阶段),如前所述,这在多线程中是不行的。解决方式是禁用掉alarm这种超时, curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L)。

这样,多线程中使用超时就安全了。但是域名解析就没了超时机制,碰到很慢的域名解析,也很麻烦。文档的建议是 Consider building libcurl with c-ares support to enable asynchronous DNS lookups, which enables nice timeouts for name resolves without signals. c-ares 是异步的 DNS 解决方案。

libcurl 多线程使用注意事项

1、问题来源,多线程使用Libcurl导致程序跑一段时间后自己退出,没有明显的异常。找不到合适的BUG。

最后通过查看资料和网上找的一些文章,发现,原来是信号处理的问题:

CURLOPT_NOSIGNAL

Pass a long. If it is 1, libcurl will not use any functions that install signal handlers or any functions that cause signals to be sent to the process. This option is mainly here to allow multi-threaded unix applications to still set/use all timeout options etc, without risking getting signals. (Added in 7.10)

If this option is set and libcurl has been built with the standard name resolver, timeouts will not occur while the name resolve takes place. Consider building libcurl with c-ares support to enable asynchronous DNS lookups, which enables nice timeouts for name resolves without signals.

Setting CURLOPT_NOSIGNAL to 1 makes libcurl NOT ask the system to ignore SIGPIPE signals, which otherwise are sent by the system when trying to send data to a socket which is closed in the other end. libcurl makes an effort to never cause such SIGPIPEs to trigger, but some operating systems have no way to avoid them and even on those that have there are some corner cases when they may still happen, contrary to our desire.

就是当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。

所以,在使用的时候把这个选项设置成1就可以了.

curl_setopt(curl, CURLOPT_NOSIGNAL, 1L);

2、关于libcurl库的初始化和关闭:curl_global_init()和curl_global_cleanup()

这两个函数并不是线程安全的。所以只能在主线程中进行一次的初始化和清除。

虽然这个不是一定就会有问题,但是如果不这样处理还是有概率发生的。

目录
相关文章
|
存储 网络安全 C++
C++ LibCurl 库的使用方法
LibCurl是一个开源的免费的多协议数据传输开源库,该框架具备跨平台性,开源免费,并提供了包括`HTTP`、`FTP`、`SMTP`、`POP3`等协议的功能,使用`libcurl`可以方便地进行网络数据传输操作,如发送`HTTP`请求、下载文件、发送电子邮件等。它被广泛应用于各种网络应用开发中,特别是涉及到数据传输的场景。
424 0
|
应用服务中间件 网络安全 数据安全/隐私保护
|
C++ Windows
64bit libcurl.lib生成步骤及注意事项详解
1、[前提]编译32bit libcurl.lib 参考文档:Using-libcurl-with-SSH-support-in-Visual-Studio-2010.pdf。下载地址:http://curl.haxx.se/libcurl/c/
444 0
64bit libcurl.lib生成步骤及注意事项详解
|
应用服务中间件
|
关系型数据库 PostgreSQL
PostgreSQL 10.1 手册_部分 IV. 客户端接口_第 33 章 libpq - C 库_33.20. 编译 libpq 程序
33.20. 编译 libpq 程序 要编译(即编译并且链接)一个使用libpq的程序,你需要做下列所有的事情: 包括libpq-fe.h头文件: #include <libpq-fe.h> 如果你无法这样做,那么你通常会从你的编译器得到像这样的错误消息: foo.
1446 0
|
数据库 Linux 安全