您的位置:逆风者 VC++ 正文
 添加时间:2007-09-01 原文发表:2007-08-31 人气:297 来源:vckbase.com

本文章共1989字,分2页,当前第1页,快速翻页:
 

使用 CInternetSession 封装多线程 http 文件下载

作者:付黎
www.crazy-bit.com
逆@风@者

源代码下载

  如何下载一个http文件?我们当然可以用socket自己实现http协议去做,但费时费力还易出bug,对于一个客户端程序稳定易维护是第一位的,所幸MS给我们提供了功能强大的internet API函数族,MFC的CInternetSession对它们进行了一些简单的封装,但如此简单的封装对我等拿来主义者来说只是个半成品。必须经过再加工才能食用。

先来介绍一下CInternetSession的使用:

下面的代码是读取链接的基本方法:


// CInternetSession在遇到一些错误时会抛出异常,因此必须包起来

TRY

{

    CInternetSession   sess ;



    // 统一以二进制方式下载

    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

   这段代码有一个问题,在获取文件大小这个地方,对于静态网页 HTTP_QUERY_CONTENT_LENGTH 查询会返回文件大小,但对于asp,php这样的动态网页,查询会返回0。必须通过不断的调用 CHttpFile::GetLength 来一点一点累加内容,就像这样:

int   n = pF->GetLength() ;

while (n)

{

    int   * p = new BYTE[n] ;

    pF->Read (p, n) ;

    delete[] p ;

    n = pF->GetLength() ;

}

不过网络断线同样会让 GetLength 返回0,必须把这种情况屏蔽掉。

if (n == 0)

{

    DWORD   dw ;

    if (::InternetQueryDataAvailable ((HINTERNET)(*pF), &dw, 0, 0) && (dw == 0))

    {

        // 到这里就代表文件下载成功了

    }

}

   OK,我们已经把机制摸清了,剩下就是把这些体力活全扔进线程里,又一个麻烦产生了:线程里如何向外界通知事件(开始下载,下载完成之类)呢?直接调用回调函数当然可以, 但这时回调函数是置于我们的线程中,造成在回调函数中对资源的访问必须非常小心,防止多线程冲突。下一步,加锁同步...。
挣扎在多线程泥潭中的人已经够多的了,其实我们有一个更安全方便的方法,借助 SendMessage 把线程里的事件发送到窗口线程统一处理,windows会帮我们把所有 消息排队执行,相当于把多线程程序转成了单线程^_^ (我一个同事把此类用于包含数百个线程的爬虫程序中,非常稳定)

封装结果及使用:

template<class T>

class FCDownloadFileWndBase : public T

{

public:

    // 默认构造函数

    FCDownloadFileWndBase () {}

    // CDialog 构造函数

    FCDownloadFileWndBase (UINT nID, CWnd* pParent) : T(nID, pParent) {}

    // CFormView 构造函数

    FCDownloadFileWndBase (UINT nID) : T(nID) {}



    // 创建一个线程下载文件URL,如果URL正在下载中,此函数什么也不做立即返回

    void DownloadFile (LPCTSTR strFileURL, int nPriority=THREAD_PRIORITY_IDLE) ;



protected:

    // 检查链接最后修改时间,有些服务器会禁止查看时间,strTime为空

    // 用户必须重载实现本接口,返回TRUE则继续下载文件,返回FALSE则不再下载文件

    virtual BOOL DownloadFile_OnCheckTime (CString strFileURL, CString strTime) =0 ;



    // 当链接成功下载完成后会调用此接口

    virtual void DownloadFile_OnFinished (CString strFileURL, char* pBuffer, int nLength) {}



    // 当IE设置代理服务器并且服务器需要帐号认证时候回调

    virtual void DownloadFile_OnProxyValidate (CString strFileURL, CString& strUsername, CString& strPassword) {}



    // 出现错误时回调

    virtual void DownloadFile_OnError (CString strFileURL) {}



    // 开始下载一个链接

    virtual void DownloadFile_OnStartDownload (CString strFileURL) {}



    // 当前进度,每下载一块数据就会回调

    virtual void DownloadFile_OnProgress (CString strFileURL, int nNow, int nTotal) {}

};

 
 
本文章更多内容1 - 2 - 下一页>>
相关文章

MFC程序员的WTL指南: Part V - 高级对话框用
SQL Server 索引结构及其使用(一)
一个简单的系列号(SN)填写器
安装钩子,托管C 中的字符串以其它
.NET 常见问答:完成器(Finalizer)、程序
用C#开发第一个WINDOWS应用程序(第一部分)
介绍两个 XML 文件操作类
浏览器的定制与扩展
用键盘操作静态链接打开应用程序中的URLs
TextFormator Framework 简介
在VC项目中使用自定义资源
用 C 语言编写 Windows 服务程序的五个步骤
UTF-7 邮件安全的 Unicode 转换编码
ADO智能开发包
解说Win32的窗口子类化
为你的MFC程序添加宏脚本语言
Island Hopper News 范例及其它
如何获取某个动态链接库的版本信息
多层图像合成修正版
在你的MFC应用程序中显示一个JPG文件

相关评论


本文章所属分类:首页 VC++

  热门关键字: