1. 程式人生 > >libcurl實現多執行緒下載器

libcurl實現多執行緒下載器


       libcurl官網(http://curl.haxx.se/)是一個很強大網路功能的庫,支援當前DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMTP, SMTPS, Telnet and TFTP. curl supports SSL certificates, HTTP POST, HTTP PUT, FTP 等基本上網路大部分的協議,據說還是linux內建的基本庫,其功能之強大可想而之,而且開源免費。

      前段時間專案要求來提高下載的速度,由於之前的下載做的很簡單是基於QT的QNetWork元件來做的,這個下載器的功能比較單一,只支援單執行緒下載,所以下載速度在檔案小的時候體現不出來,但在檔案大的時候很明顯比較慢,所以才產生了要更新下載器的想法,能夠採用的庫很多,但綜合考慮,為了相容多種系統,還是用開源的libcurl比較好。

    libcurl初始用起來很簡單,要實現一個基本互動,只要進行基本的三步就可以: curl_easy_init、curl_easy_setopt、curl_easy_perform,這裡關鍵在於curl_easy_setopt,這裡面可以設定很多選項,你所要的功能基本上都在這裡得到體現。閒話少說,現在庫選好了,該談談策略的問題,既然採用多執行緒下載,總得有一個基本的思想,本專案中我的思路如下:對於一個指定長度的檔案F,假如它的長度為L,若劃分共n個執行緒來下,則每個執行緒負責下載的大小為L/n,就這樣,執行緒1負責下載第一塊L/n,執行緒2負責下載第二塊L/n,依次類推,每個執行緒的負載都一樣,這樣設計比較簡單,這樣的設計避免了執行緒的切換,每個執行緒就是執行一個任務,就只下載自己所負責的那一區間。具體執行緒是採用pthread庫,也是一個開源的,跟libcurl配合的很好。

    下載接收到的資料會寫到一個臨時檔案裡面去,臨時檔案的結構如下:

    

   執行緒寫資料區間對應執行緒的下載資料區間

   輔助資訊X:儲存每個執行緒的負責下載的開始位置begPos,要下載的資料長度blockLen,已經接收的資料長度recvLen

   輔助資訊Y:要下載的檔案長度L

   輔助資訊是斷點續傳的根據

  臨時檔案結構定好,就開始下載了

一、正常下載流程

       正常下載流程包括初始化、執行緒下載區間劃分、多執行緒下載資料,下載容錯處理幾方面

      1、下載初始化,主要為了獲取下載的檔案大小,下載是否支援多執行緒等屬性;獲取檔案大小是為了確定劃分執行緒個數,在本專案中執行緒最小分塊為5M,即若一個下載檔案大小為10M,則開兩個執行緒,每個執行緒負責下載5M,若下載檔案大小為11M,則就開執行緒個數為:11/5=2.2,即開3個執行緒,每個執行緒接收資料大小為11M/3,依次類推。

     判斷是否支援多執行緒,是採用向服務端傳送"Range:0-"請求,看返回的報文,若報文中有"Content-Range: bytes"部分,則表示伺服器支援分片傳輸,即支援多執行緒下載,否則此資源連結只能採用單執行緒下載。

    2、執行緒下載區間劃分:要所初始化得到的檔案大小及是否支援多執行緒的屬性來判斷,若不支援多執行緒,那隻能開一個執行緒,來下載整個檔案;若支援多執行緒,則根據大小及執行緒最小分塊來確定每個執行緒的下載區間,具體可參考1中說明

  3、多執行緒下載資料:根據1、2確定了每個執行緒的下載區間,就開相應個數的執行緒來執行下載,下載接收的資料全部寫入臨時檔案,且要及時更新臨時檔案尾部資訊

  4、下載容錯處理:這個要重點說明一下,因為實際的網路環境都是很複雜的,網路效能也是時好時壞,所以一定要做好容錯;本專案中的容錯基本上主是增量重試

       若一次下載失敗,就要等待一段時間來進行重試,這樣雖然不能根治下載失敗,但在很大程式上緩解了下載失敗的可能。

二、斷點續傳流程

     斷點續傳跟正常下載不一樣,它會先去讀上一次的下載臨時檔案,重點是最臨時檔案尾部資訊,來還原上一次下載時的場景,繼續下載; 

     在這裡特別要提一下:若上一次的下載是不支援斷點綾傳的,則會直接從0開始下載;否則是接著上次的進度開始下載。

三、下載注意事項:

    1、重定向的問題:重定向可以用curl中的選項CURLOPT_FOLLOWLOCATION來設定,也可以自己解析重定向後的URL

    2、下載中最好都用短連線,慎用長連線;

    3、下載中超時設定,可以用連線超時CURLOPT_CONNECTTIMEOUT項來設定,當然也可以設定CURLOPT_LOW_SPEED_LIMIT、CURLOPT_LOW_SPEED_TIME這兩個選項來限制接收超時

四、總結:libcurl功能很強大,經測試速度比一般下載器要快一倍不止,檔案越大,多執行緒的效能就越明顯,下載本身並不複雜,但要優化效能的話,還需要做各種深究,如DNS快取,連線重用等機制,這裡恕在下才學淺,暫時未深究到這個層次。

原始碼下載:http://download.csdn.net/detail/u012532305/9582417

歡迎大家拍磚!