WEB开发网
开发学院软件开发VC 使用 CInternetSession 封装多线程 http 文件下载... 阅读

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

 2007-03-17 22:00:45 来源:WEB开发网   
核心提示:本文示例源代码或素材下载 如何下载一个http文件?我们当然可以用socket自己实现http协议去做,但费时费力还易出bug,使用 CInternetSession 封装多线程 http 文件下载,对于一个客户端程序稳定易维护是第一位的,所幸MS给我们提供了功能强大的internet API函数族,防止多线程

本文示例源代码或素材下载

如何下载一个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,我们已经把机制摸清了,剩下就是把这些体力活全扔进线程里,又一个麻烦产生了:线程里如何向外界通知事件(开始下载,下载完成之类)呢?直接调用回调函数当然可以,但这时回调函数是置于我们的线程中,造成在回调函数中对资源的访问必须非常小心,防止多线程冲突。下一步,加锁同步...。

1 2  下一页

Tags:使用 CInternetSession 封装

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接