Libcurl實現斷點續傳


一、LIbcurl簡單介紹

    其實關於Liccurl的介紹最好的是看官方文檔:http://curl.haxx.se/ 幾乎大部分的信息里面都能夠查找到。

    在這邊簡要介紹:

    1)跨平台特性,幾乎所有平台都可以使用

    2)有許多其他語言的包裝,如PHP、PYTHON等,也就是很多語言都可以使用libcurl

    3)Libcurl的所有接口被設計成線程安全(線程安全的意思是:在多線程之中可以同時調用一個API而不會互相影響,也就是函數可重入),另外要特別注意的是,任何一個libcurl的handle都不應該在多個線程之間共享,另外若使用HTTPS、FTPS需要OpenSSL或GnuTls的支持。

    4)支持IPV6,前提是在編譯的時候打開相應的選項

    5)Libcurl性能很不錯,但是若通過其他語言(非C語言)性能會有一定減弱,這和其他語言本身有關系

    6)Libcurl提供三種handle:easy_handle、multi_handle、share_handle

    easy_handle:為libcurl的最基礎部分,所有的操作都是在easy_handle上進行的,比如發送、請求數據都是在其上進行的。如果直接在easy_handle執行操作 curl_easy_perform 函數是阻塞的(即需要等到完成才返回)

    multi_handle:libcurl為異步操作提供的接口,允許調用方在一個線程中處理多個操作(就是easy_handle上的操作,注意是單線程下的),內部multi_handle采用堆棧的方式保存多個easy_handle,然后在一個線程中可以同時對多個easy_handle進行處理,multi_handle的執行操作 curl_multi_perform 函數是立即返回的,不會阻塞

    share_handle:有時候多個easy_handle需要分享一些信息,比如cookie,當一個連接獲取一個新的cookie,就可以將這個cookie共享到所有的連接上

二、一些應用實例

1、實現cookie共享

  1)場景:客戶端與服務器之間為了提高傳輸性能,建立了多個http連接。

    服務區為了管理這個客戶端的信息要使用一個會話來保存該客戶端的一些信息,為了方便將會話信息保存在cookie之中。

    當服務器檢查到某個http連接沒有帶cookie或者cookie失效時,會自動設置一個新的cookie。

    客戶端希望當獲取新的cookie時,馬上生效到所有到該服務器的http連接上。

  2)解決方案:使用libcurl提供的share_handle在多個http連接之間實現共享cookie操作

    CURLSH *pShared = curl_share_init( );   ///創建一個share_handle

    curl_share_setopt(pShared,CURLSHOPT_SHARE,CURL_LOCK_DATA_COOKIE);   ///設置在蓋share_handle上共享的cookie

    CURL* pCurl = curl_easy_init();

    curl_easy_setopt(pCurl, CURLOPT_SHARE, pShared);    ///創建easy_handle並設置器share屬性

    curl_easy_setopt(pCurl,CURLOPT_COOKIEFILE,"");    ///設置給easy_handle的連接添加上cookie支持

    ///可以以同樣的方式添加多個easy_handle到該share_handle之中實現cookie共享,然后再easy_handle上執行的操作就能夠自動共享cookie

2、實現HEAD請求

  1)場景:有時候你想查詢服務器某種資源的狀態,比如某個文件的屬性:修改時間,大小等等,但是並不像具體得到該文件,這時就是HEAD請求出場的時候

  2)解決方案:起始使用libcurl很容易實現

    主要設置該easy_handle的NOBODY屬性即可

    curl_easy_setopt(curl,CURLOPT_NOBODY ,1L );   ///告訴libcurl我想發起一個HEAD請求

3、實現斷點下載

  1)場景:當從服務器下載一個大文件時,可能需要相當長的時間來完成,在這過程中若出現網絡超時或者客戶端或者服務器宕機的情況時,若恢復時再從頭開始下載勢必浪費,這時可以使用從斷點處下載。

  2)解決方案:在HTTP的GET請求之中可以設置range頭部告訴服務器要從指定位置取數據,libcurl如下:

  curl_easy_setopt(curl, CURLOPT_RANGE,"100-");   //設置了該屬性后,發送的GET請求,會有 “Range:100-“ 頭部告訴服務器需要100字節后的數據

4、實現斷點上傳

  1)場景:類似斷點下載,就是向服務器傳輸了一部分數據后異常,當服務恢復時就可以使用斷點上傳

  2)解決方案:需要兩個步驟來實現斷點上傳,第一個不使用一個HEAD請求,查詢服務器已經保存的該文件大小,服務器應該在HEAD應答的 Content-Length 頭部中說明該文件服務器持有的大小,然后客戶端在通過一個POST或者PUT請求並且設置 Content_Range 告訴服務器上傳的位置。

    發起HEAD請求上面已經敘述,這里特別之處在於需要讀取服務器對HEAD應答報文的Content_Length部分,需要告訴libcurl你要讀取header內容:

    curl_easy_setopt(m_pCURL, CURLOPT_NOBODY, 1L);    ///告訴libcurl發起HEAD請求

    curl_easy_setopt(m_pCURL, CURLOPT_HEADERFUNCTION, pIoReadHeader_cb);    ///告訴libcurl要讀取應答報文的HEADER,當libcurl收到一個完整的header時就會調用該回調函數,其格式如下:int OnReadHeader(char *ptr, size_t size, size_t nmemb, void *userdata) 只要在回調函數中查看是否包含 Content-Length 字符串然后解析后面的內容即可。
    curl_easy_setopt(m_pCURL, CURLOPT_WRITEHEADER, pPrivateData);  ///設置私有數據,該數據會被傳遞到回調函數的 userdata 參數之中

    ///假如收到服務器返回的Content_Length為100,這時候POST時就只要從100字節開始上傳,並且設置Content_Range頭部標示出開始位置:

    ///注意格式: Content_Range:begin-end/size   以這里為例,假如文件大小為1000字節,從100開始那么Content_range應該就是 100-999/1000

    curl_easy_setopt(curl, CURLOPT_RANGE, "100-999");   ///設置前面部分 100-999

    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)1000);   ///設置size部分為1000

    然后就可以使用WRITEFUNCTION等函數進行上傳了。

    

    

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM