• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            使用 CInternetSession 封裝多線程 http 文件下載

            使用 CInternetSession 封裝多線程 http 文件下載

            作者:付黎
            www.crazy-bit.com

            源代碼下載
            /*

            URLDownloadToFile();

            主要是下載升級包..............................

            */
              如何下載一個http文件?我們當然可以用socket自己實現(xiàn)http協(xié)議去做,但費時費力還易出bug,對于一個客戶端程序穩(wěn)定易維護是第一位的,所幸MS給我們提供了功能強大的internet API函數(shù)族,MFC的CInternetSession對它們進行了一些簡單的封裝,但如此簡單的封裝對我等拿來主義者來說只是個半成品。必須經(jīng)過再加工才能食用。

            先來介紹一下CInternetSession的使用:

            下面的代碼是讀取鏈接的基本方法:

            // CInternetSession在遇到一些錯誤時會拋出異常,因此必須包起來
            TRY
            {
                  CInternetSession     sess ;

                  
            // 統(tǒng)一以二進制方式下載
                  DWORD         dwFlag = INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_RELOAD ;
                  CHttpFile     
            * pF = (CHttpFile*)sess.OpenURL(strFilename, 1, dwFlag); ASSERT(pF);
                  
            if (!pF)
                      
            {AfxThrowInternetException(1);}

                  
            // 得到文件大小
                  CString        str ;
                  pF
            ->QueryInfo (HTTP_QUERY_CONTENT_LENGTH, str) ;
                  
            int     nFileSize = _ttoi(str) ;

                  
            char     * p = new[nFileSize] ;
                  
            while (true)
                  
            {
                      
            // 每次下載8Kb
                      int     n = pF->Read (p, (nFileSize < 8192? nFileSize : 8192) ;
                      
            if (n <= 0)
                          
            break ;
                      p 
            += n ; nFileSize -= n ;
                  }

                  delete[] p ;
                  delete pF ;
            }

            CATCH_ALL(e) 
            {}
            END_CATCH_ALL
              這段代碼有一個問題,在獲取文件大小這個地方,對于靜態(tài)網(wǎng)頁 HTTP_QUERY_CONTENT_LENGTH 查詢會返回文件大小,但對于asp,php這樣的動態(tài)網(wǎng)頁,查詢會返回0。必須通過不斷的調(diào)用 CHttpFile::GetLength 來一點一點累加內(nèi)容,就像這樣:
            int     n = pF->GetLength() ;
            while (n)
            {
                  
            int     * p = new BYTE[n] ;
                  pF
            ->Read (p, n) ;
                  delete[] p ;
                  n 
            = pF->GetLength() ;
            }


            不過網(wǎng)絡(luò)斷線同樣會讓 GetLength 返回0,必須把這種情況屏蔽掉。 
            if (n == 0)
            {
                  DWORD     dw ;
                  
            if (::InternetQueryDataAvailable ((HINTERNET)(*pF), &dw, 00&& (dw == 0))
                  
            {
                      
            // 到這里就代表文件下載成功了
                  }

            }


               OK,我們已經(jīng)把機制摸清了,剩下就是把這些體力活全扔進線程里,又一個麻煩產(chǎn)生了:線程里如何向外界通知事件(開始下載,下載完成之類)呢?直接調(diào)用回調(diào)函數(shù)當然可以,但這時回調(diào)函數(shù)是置于我們的線程中,造成在回調(diào)函數(shù)中對資源的訪問必須非常小心,防止多線程沖突。下一步,加鎖同步...。
            掙扎在多線程泥潭中的人已經(jīng)夠多的了,其實我們有一個更安全方便的方法,借助 SendMessage 把線程里的事件發(fā)送到窗口線程統(tǒng)一處理,windows會幫我們把所有消息排隊執(zhí)行,相當于把多線程程序轉(zhuǎn)成了單線程^_^ (我一個同事把此類用于包含數(shù)百個線程的爬蟲程序中,非常穩(wěn)定)

            封裝結(jié)果及使用:
            template<class T>
            class FCDownloadFileWndBase : public T
            {
            public:
                  
            // 默認構(gòu)造函數(shù)
                  FCDownloadFileWndBase () {}
                  
            // CDialog 構(gòu)造函數(shù)
                  FCDownloadFileWndBase (UINT nID, CWnd* pParent) : T(nID, pParent) {}
                  
            // CFormView 構(gòu)造函數(shù)
                  FCDownloadFileWndBase (UINT nID) : T(nID) {}

                  
            // 創(chuàng)建一個線程下載文件URL,如果URL正在下載中,此函數(shù)什么也不做立即返回
                  void DownloadFile (LPCTSTR strFileURL, int nPriority=THREAD_PRIORITY_IDLE) ;

            protected:
                  
            // 檢查鏈接最后修改時間,有些服務(wù)器會禁止查看時間,strTime為空
                  
            // 用戶必須重載實現(xiàn)本接口,返回TRUE則繼續(xù)下載文件,返回FALSE則不再下載文件
                  virtual BOOL DownloadFile_OnCheckTime (CString strFileURL, CString strTime) =0 ;

                  
            // 當鏈接成功下載完成后會調(diào)用此接口
                  virtual void DownloadFile_OnFinished (CString strFileURL, char* pBuffer, int nLength) {}

                  
            // 當IE設(shè)置代理服務(wù)器并且服務(wù)器需要帳號認證時候回調(diào)
                  virtual void DownloadFile_OnProxyValidate (CString strFileURL, CString& strUsername, CString& strPassword) {}

                  
            // 出現(xiàn)錯誤時回調(diào)
                  virtual void DownloadFile_OnError (CString strFileURL) {}

                  
            // 開始下載一個鏈接
                  virtual void DownloadFile_OnStartDownload (CString strFileURL) {}

                  
            // 當前進度,每下載一塊數(shù)據(jù)就會回調(diào)
                  virtual void DownloadFile_OnProgress (CString strFileURL, int nNow, int nTotal) {}
            }
            ;
            使用起來非常簡單,讓你的窗口從它派生,然后選擇你感興趣的事件重載之即可。

            幾點說明:

            1. 本類會自動使用IE里的連接設(shè)置,如果代理服務(wù)器需要帳號驗證,會回調(diào) DownloadFile_OnProxyValidate 讓用戶輸入帳號密碼;
            2. 因為使用了模版,所以不支持MFC丑陋的dynamic機制:-( ,請把 DECLARE_DYNAMIC 和 IMPLEMENT_DYNAMIC 宏從你的類中移除。如果你需要運行時類型檢查,可以用C++的RTTI機制dynamic_cast/typeid;

            download article source from here:Download.rar

            posted on 2007-10-15 16:57 楊粼波 閱讀(841) 評論(1)  編輯 收藏 引用

            評論

            # re: 使用 CInternetSession 封裝多線程 http 文件下載[未登錄] 2007-10-17 22:54 wen

            thanks for you tech
            i can't download sample ,
            please check it  回復  更多評論   

            久久精品中文字幕一区| 怡红院日本一道日本久久 | 青青草原综合久久大伊人导航| 久久亚洲国产欧洲精品一| 久久中文字幕无码专区| 亚洲国产一成人久久精品| 1000部精品久久久久久久久| 久久精品一区二区影院| 精品无码久久久久国产| 亚洲国产日韩欧美综合久久| 精品国产福利久久久| 久久婷婷色香五月综合激情| 国产成人精品免费久久久久| 亚洲精品国精品久久99热| 亚洲国产精品久久久久婷婷老年 | 色偷偷91久久综合噜噜噜噜| 久久久久亚洲av无码专区导航| 久久久久亚洲AV无码去区首| 国产麻豆精品久久一二三| 一级女性全黄久久生活片免费 | 国内精品久久久久影院日本| 日本国产精品久久| 久久99精品久久久久久9蜜桃| 大伊人青草狠狠久久| 亚洲av日韩精品久久久久久a| 内射无码专区久久亚洲| 久久精品国产只有精品66 | 久久久久久久久66精品片| 精品多毛少妇人妻AV免费久久| 精品国产一区二区三区久久| 国内精品久久久久影院一蜜桃| 色欲久久久天天天综合网精品| 麻豆久久| 中文字幕无码久久精品青草| 亚洲一区精品伊人久久伊人| 亚洲v国产v天堂a无码久久| 久久亚洲精品无码观看不卡| 日韩亚洲国产综合久久久| 中文成人无码精品久久久不卡| 亚洲午夜精品久久久久久浪潮| 97香蕉久久夜色精品国产|