日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libcurl编程

發(fā)布時(shí)間:2024/2/28 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libcurl编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?假設(shè)你要獲取URL所表示的遠(yuǎn)程主機(jī)上的資源。你需要寫一段程序用來完成數(shù)據(jù)傳輸,你可能希望直接保存接收到的數(shù)據(jù)而不是簡(jiǎn)單的在輸出窗口中打印它們。所以,你必須首先寫一個(gè)回調(diào)函數(shù)用來保存接收到的數(shù)據(jù)。回調(diào)函數(shù)的原型如下:

size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);

??? 可以使用下面的語句來注冊(cè)回調(diào)函數(shù),回調(diào)函數(shù)將會(huì)在接收到數(shù)據(jù)的時(shí)候被調(diào)用:

curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data);

??? 可以給回調(diào)函數(shù)提供一個(gè)自定義參數(shù),libcurl不處理該參數(shù),只是簡(jiǎn)單的傳遞:

curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &internal_struct);

??? 如果你沒有通過CURLOPT_WRITEFUNCTION屬性給easy handle設(shè)置回調(diào)函數(shù),libcurl會(huì)提供一個(gè)默認(rèn)的回調(diào)函數(shù),它只是簡(jiǎn)單的將接收到的數(shù)據(jù)打印到標(biāo)準(zhǔn)輸出。你也可以通過 CURLOPT_WRITEDATA屬性給默認(rèn)回調(diào)函數(shù)傳遞一個(gè)已經(jīng)打開的文件指針,用于將數(shù)據(jù)輸出到文件里。

??? 下面是一些平臺(tái)相關(guān)的注意點(diǎn)。在一些平臺(tái)上,libcurl不能直接操作由應(yīng)用程序打開的文件。所以,如果使用默認(rèn)的回調(diào)函數(shù),同時(shí)通過 CURLOPT_WRITEDATA屬性給easy handle傳遞一個(gè)文件指針,應(yīng)用程序可能會(huì)執(zhí)行失敗。如果你希望自己的程序能跑在任何系統(tǒng)上,你必須避免出現(xiàn)這種情況。

??? 如果以win32動(dòng)態(tài)連接庫的形式來使用libcurl,在設(shè)置CURLOPT_WRITEDATA屬性時(shí),你必須同時(shí) 使用CURLOPT_WRITEFUNCTION來注冊(cè)回調(diào)函數(shù)。否則程序會(huì)執(zhí)行失敗(筆者嘗試只傳遞一個(gè)打開的文件指針而不顯式設(shè)置回調(diào)函數(shù),程序并沒有崩潰。可能是我使用的方式不正確。)。

??? 當(dāng)然,libcurl還支持許多其他的屬性,在接下來的篇幅里,你將會(huì)逐步地接觸到它們。調(diào)用下面的函數(shù),將執(zhí)行真正的數(shù)據(jù)通信:

success = curl_easy_perform(easy_handle);

?curl_easy_perfrom將連接到遠(yuǎn)程主機(jī),執(zhí)行必要的命令,并接收數(shù)據(jù)。當(dāng)接收到數(shù)據(jù)時(shí),先前設(shè)置的回調(diào)函數(shù)將被調(diào)用。libcurl可能一次只接收到1字節(jié)的數(shù)據(jù),也可能接收到好幾K的數(shù)據(jù),libcurl會(huì)盡可能多、及時(shí)的將數(shù)據(jù)傳遞給回調(diào)函數(shù)。回調(diào)函數(shù)返回接收的數(shù)據(jù)長(zhǎng)度。如果回調(diào)函數(shù)返回的數(shù)據(jù)長(zhǎng)度與傳遞給它的長(zhǎng)度不一致(即返回長(zhǎng)度 != size * nmemb),libcurl將會(huì)終止操作,并返回一個(gè)錯(cuò)誤代碼。

??? 當(dāng)數(shù)據(jù)傳遞結(jié)束的時(shí)候,curl_easy_perform將返回一個(gè)代碼表示操作成功或失敗。如果需要獲取更多有關(guān)通信細(xì)節(jié)的信息,你可以設(shè)置 CURLOPT_ERRORBUFFER屬性,讓libcurl緩存許多可讀的錯(cuò)誤信息。

??? easy handle在完成一次數(shù)據(jù)通信之后可以被重用。這里非常建議你重用一個(gè)已經(jīng)存在的easy handle。如果在完成數(shù)據(jù)傳輸之后,你創(chuàng)建另一個(gè)easy handle來執(zhí)行其他的數(shù)據(jù)通信,libcurl在內(nèi)部會(huì)嘗試著重用上一次創(chuàng)建的連接。

??? 對(duì)于有些協(xié)議,下載文件可能包括許多復(fù)雜的子過程:日志記錄、設(shè)置傳輸模式、選擇當(dāng)前文件夾,最后下載文件數(shù)據(jù)。使用libcurl,你不需要關(guān)心這一切,你只需簡(jiǎn)單地提供一個(gè)URL,libcurl會(huì)給你做剩余所有的工作。

多線程問題?
??? 首先一個(gè)基本原則就是:絕對(duì)不應(yīng)該在線程之間共享同一個(gè)libcurl handle,不管是easy handle還是multi handle(將在下文中介紹)。一個(gè)線程每次只能使用一個(gè)handle。

??? libcurl是線程安全的,但有兩點(diǎn)例外:信號(hào)(signals)和SSL/TLS handler。 信號(hào)用于超時(shí)失效名字解析(timing out name resolves)。libcurl依賴其他的庫來支持SSL/STL,所以用多線程的方式訪問HTTPS或FTPS的URL時(shí),應(yīng)該滿足這些庫對(duì)多線程操作的一些要求。

? libcurl提供協(xié)議無關(guān)的方式進(jìn)行數(shù)據(jù)傳輸。所以上傳一個(gè)文件到FTP服務(wù)器,跟向HTTP服務(wù)器提交一個(gè)PUT請(qǐng)求的操作方式是類似的:

1. 創(chuàng)建easy handle或者重用先前創(chuàng)建的easy handle。

2. 設(shè)置CURLOPT_URL屬性。

3. 編寫回調(diào)函數(shù)。在執(zhí)行上傳的時(shí)候,libcurl通過回調(diào)函數(shù)讀取要上傳的數(shù)據(jù)。(如果要從遠(yuǎn)程服務(wù)器下載數(shù)據(jù),可以通過回調(diào)來保存接收到的數(shù)據(jù)。)回調(diào)函數(shù)的原型如下:
size_t function(char *bufptr, size_t size, size_t nitems, void *userp);

??? bufptr指針表示緩沖區(qū),用于保存要上傳的數(shù)據(jù),size * nitems是緩沖區(qū)數(shù)據(jù)的長(zhǎng)度,userp是一個(gè)用戶自定義指針,libcurl不對(duì)該指針作任何操作,它只是簡(jiǎn)單的傳遞該指針。可以使用該指針在應(yīng)用程序與libcurl之間傳遞信息。

4. 注冊(cè)回調(diào)函數(shù),設(shè)置自定義指針。語法如下:?
// 注冊(cè)回調(diào)函數(shù)
curl_easy_setopt(easy_handle, CURLOPT_READFUNCTION, read_function);?
// 設(shè)置自定義指針
curl_easy_setopt(easy_handle, CURLOPT_READDATA, &filedata);

5. 告訴libcurl,執(zhí)行的是上傳操作。?
curl_easy_setopt(easy_handle, CURLOPT_UPLOAD, 1L);

??? 有些協(xié)議在沒有預(yù)先知道上傳文件大小的情況下,可能無法正確判斷上傳是否結(jié)束,所以最好預(yù)先使用CURLOPT_INFILESIZE_LARGE屬性:告訴它要上傳文件的大小:?
/* in this example, file_size must be an curl_off_t variable */
curl_easy_setopt(easy_handle, CURLOPT_INFILESIZE_LARGE, file_size);


??? 下面的這個(gè)例子演示了如何獲取網(wǎng)頁源碼,將其保存到本地文件,并同時(shí)將獲取的源碼輸出到控制臺(tái)上。
/**
* @brief libcurl接收到數(shù)據(jù)時(shí)的回調(diào)函數(shù)
*
* 將接收到的數(shù)據(jù)保存到本地文件中,同時(shí)顯示在控制臺(tái)上。
*
* @param [in] buffer 接收到的數(shù)據(jù)所在緩沖區(qū)
* @param [in] size 數(shù)據(jù)長(zhǎng)度
* @param [in] nmemb 數(shù)據(jù)片數(shù)量
* @param [in/out] 用戶自定義指針
* @return 獲取的數(shù)據(jù)長(zhǎng)度
*/

size_t process_data(void *buffer, size_t size, size_t nmemb, void *user_p)
{
FILE *fp = (FILE *)user_p;
size_t return_size = fwrite(buffer, size, nmemb, fp);
cout << (char *)buffer << endl; return return_size;
}


int main(int argc, char **argv)
{
// 初始化libcurl
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code)
{
cerr << "init libcurl failed." << endl;
return -1;
}

// 獲取easy handle
CURL *easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
cerr << "get a easy handle failed." << endl;
curl_global_cleanup(); return -1;
}

FILE *fp = fopen("data.html", "ab+"); //?
// 設(shè)置easy handle屬性
curl_easy_setopt(easy_handle, CURLOPT_URL,?http://blog.csdn.net/JGood);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, &process_data);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, fp);


// 執(zhí)行數(shù)據(jù)請(qǐng)求
curl_easy_perform(easy_handle);

// 釋放資源

fclose(fp);
curl_easy_cleanup(easy_handle);
curl_global_cleanup();

return 0;
}


總結(jié)

以上是生活随笔為你收集整理的libcurl编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。