最近需要用curl來發送http請求,遇到了不少問題,查了不少資料,都是零零散散的,現在總結下。
1、移植編譯
1 ./configure --prefix=$(PWD)/build --host=arm-XXX-linux;make ;make install
這步基本都沒有問題,生成的動態鏈接庫libcurl.a,可以直接給應用程序去使用。
2、API使用
1)全局初始化 curl_global_init(CURL_GLOBAL_ALL);
2)通過curl_easy_init得到一個CURL指針m_pCurl
3)通過curl_formadd封裝參數
通過curl_easy_setopt設置各種選項
通過curl_easy_perform執行curl的各種操作
4)curl_easy_getinfo 獲得http返回的狀態碼
5)curl_easy_cleanup釋放CURL指針
6)curl_global_cleanup釋放全局對象
3、http的響應內容獲取
先通過 curl_easy_setopt設置CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA選項
struct CResponseResult
{
int m_iResponseSize; // 響應的實際大小
char* m_p_responseBuffer; // 指向響應內存的指針
};
size_t ReviceData(char *buffer, size_t size, size_t nmemb, CResponseResult & stream) { size_t total = size * nmemb;
if (total <= 0 || (stream.m_iResponseSize + total) > MAX_RESPONSE_DATA_BUF_SIZE)
{
return 0;
}
memcpy(&stream.m_p_responseBuffer[stream.m_iResponseSize], buffer, total);
stream.m_iResponseSize += total;
return total; } // 每次發請求前,把buffer清空下
memset(m_ResponseResult.m_p_responseBuffer, 0, MAX_RESPONSE_DATA_BUF_SIZE);
m_ResponseResult.m_iResponseSize = 0;
curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, ReviceData); curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &m_ResponseResult);
當有響應回來的時候,會觸發ReviceData函數,在這個回調函數,會把響應的內容,賦值給out變量,這樣響應就取得了。
4、遇到的一些問題
curl_easy_setopt(m_pCurl, CURLOPT_CONNECTTIMEOUT, 4L);
curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, 25L);
設置了超時時間后(一個是等待連接的時間,一個是等待接收響應的時間)一旦域名解析失敗,程序會莫名的掛掉,而且每次掛掉的地方都不一樣。當時也是通過一點一點注釋代碼,才定位到這兩行代碼。
coredump的原因是因為curl的DNS解析超時控制是使用SIGALARM實現的。
這樣導致發現SIGALARM會出現多線程修改同一個全局變量,由此產生了COREDUMP。
問題發生的前提是設置了CURLOPT_TIMEOUT或CURLOPT_CONNECTTIMEOUT,並且值不為0。
解決辦法:
1) 設置CURLOPT_NOSIGNAL的值為1
curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1);
設置之后,發現的確不會coredump了,但是設置的超時時間沒有用了,需要等很久,才能出結果。
2) 使用c-ares(configure時指定參數--enable-ares)
使用這個方法比較好,不會coredump,而且超時時間設置后生效。
下面介紹下這個方法:
a、下載cares的源碼,進行編譯移植
https://c-ares.haxx.se/
編譯方法和curl的編譯方法類似,都是通過configure ,最終生成libcares.a
b、修改curl源碼里的configure文件
找到下面的代碼,添加embedded_ares="yes",箭頭所指的地方,不然check
的時候,會報c-ares library defective or too old
c、重新編譯curl
./configure --enable-ares=$(PWD)/depends --prefix=$(PWD)/build --host=arm-XXX-linux;make ;make install
這里指定了enable-ares使用的libares所在的目錄。depends目錄下需要再建立一個子目錄lib,在子目錄下放入libcares.a即可。
還要把libcares的頭文件都拷貝到curl主目錄里的lib目錄里,這樣編譯就不會出錯了。