使用 CInternetSession 封装多线程 http 文件下载
2007-03-17 22:00:45 来源:WEB开发网本文示例源代码或素材下载
如何下载一个http文件?我们当然可以用socket自己实现http协议去做,但费时费力还易出bug,对于一个客户端程序稳定易维护是第一位的,所幸MS给我们提供了功能强大的internet API函数族,MFC的CInternetSession对它们进行了一些简单的封装,但如此简单的封装对我等拿来主义者来说只是个半成品。必须经过再加工才能食用。
先来介绍一下CInternetSession的使用:
下面的代码是读取链接的基本方法:// CInternetSession在遇到一些错误时会抛出异常,因此必须包起来
这段代码有一个问题,在获取文件大小这个地方,对于静态网页 HTTP_QUERY_CONTENT_LENGTH 查询会返回文件大小,但对于asp,php这样的动态网页,查询会返回0。必须通过不断的调用 CHttpFile::GetLength 来一点一点累加内容,就像这样:
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_ALLint n = pF->GetLength() ;
不过网络断线同样会让 GetLength 返回0,必须把这种情况屏蔽掉。
while (n)
{
int * p = new BYTE[n] ;
pF->Read (p, n) ;
delete[] p ;
n = pF->GetLength() ;
}if (n == 0)
OK,我们已经把机制摸清了,剩下就是把这些体力活全扔进线程里,又一个麻烦产生了:线程里如何向外界通知事件(开始下载,下载完成之类)呢?直接调用回调函数当然可以,但这时回调函数是置于我们的线程中,造成在回调函数中对资源的访问必须非常小心,防止多线程冲突。下一步,加锁同步...。
{
DWORD dw ;
if (::InternetQueryDataAvailable ((HINTERNET)(*pF), &dw, 0, 0) && (dw == 0))
{
// 到这里就代表文件下载成功了
}
}
Tags:使用 CInternetSession 封装
编辑录入:爽爽 [复制链接] [打 印]更多精彩
赞助商链接