(1), 超時(shí)(timeout)
libcurl 是 一個(gè)很不錯(cuò)的庫,支持http,ftp等很多的協(xié)議。使用庫最大的心得就是,不仔細(xì)看文檔,僅僅看著例子就寫程序,是一件危險(xiǎn)的事情。我的程序崩潰了,我 懷疑是自己代碼寫的問題,后來發(fā)現(xiàn)是庫沒用對。不仔細(xì)看文檔(有時(shí)候文檔本身也比較差勁,這時(shí)除了看仔細(xì)外,還要多動腦子,考慮它是怎么實(shí)現(xiàn)的),后果很 嚴(yán)重。不加思索的使用別人的庫或者代碼,有時(shí)候很愜意,但是出問題時(shí),卻是寢食難安的。
1. CURLcode curl_global_init(long flags); 在多線程應(yīng)用中,需要在主線程中調(diào)用這個(gè)函數(shù)。這個(gè)函數(shù)設(shè)置libcurl所需的環(huán)境。通常情況,如果不顯式的調(diào)用它,第一次調(diào)用 curl_easy_init()時(shí),curl_easy_init 會調(diào)用 curl_global_init,在單線程環(huán)境下,這不是問題。但是多線程下就不行了,因?yàn)閏url_global_init不是線程安全的。在多個(gè)線 程中調(diào)用curl_easy_int,然后如果兩個(gè)線程同時(shí)發(fā)現(xiàn)curl_global_init還沒有被調(diào)用,同時(shí)調(diào)用 curl_global_init,悲劇就發(fā)生了。這種情況發(fā)生的概率很小,但可能性是存在的。
2. libcurl 有個(gè)很好的特性,它甚至可以控制域名解析的超時(shí)。但是在默認(rèn)情況下,它是使用alarm + siglongjmp 實(shí)現(xiàn)的。用alarm在多線程下做超時(shí),本身就幾乎不可能。如果只是使用alarm,并不會導(dǎo)致程序崩潰,但是,再加上siglongjmp,就要命了 (程序崩潰的很可怕,core中幾乎看不出有用信息),因?yàn)槠湫枰粋€(gè)sigjmp_buf型的全局變量,多線程修改它。(通常情況下,可以每個(gè)線程一個(gè) sigjmp_buf 型的變量,這種情況下,多線程中使用 siglongjmp 是沒有問題的,但是libcurl只有一個(gè)全局變量,所有的線程都會用)。
具體是類似 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L) 的超時(shí)設(shè)置,導(dǎo)致alarm的使用(估計(jì)發(fā)生在域名解析階段),如前所述,這在多線程中是不行的。解決方式是禁用掉alarm這種超時(shí), curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L)。
這樣,多線程中使用超時(shí)就安全了。但是域名解析就沒了超時(shí)機(jī)制,碰到很慢的域名解析,也很麻煩。文檔的建議是 Consider building libcurl with c-ares support to enable asynchronous DNS lookups, which enables nice timeouts for name resolves without signals. c-ares 是異步的 DNS 解決方案。
引自:http://gcoder.blogbus.com/logs/54871550.html
調(diào)用libcurl下載,然后使用netstat查看發(fā)現(xiàn)有大量的TCP連接保持在CLOSE_WAIT狀態(tài)
查看libcurl的文檔說明,有這樣一個(gè)選項(xiàng):
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).
也就是說,默認(rèn)情況下libcurl完成一個(gè)任務(wù)以后,出于重用連接的考慮不會馬上關(guān)閉
如果沒有新的TCP請求來重用這個(gè)連接,那么只能等到CLOSE_WAIT超時(shí),這個(gè)時(shí)間默認(rèn)在7200秒甚至更高,太多的CLOSE_WAIT連接會導(dǎo)致性能問題
解決方法:
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
最好再修改一下TCP參數(shù)調(diào)低CLOSE_WAIT和TIME_WAIT的超時(shí)時(shí)間