[转]VC++的INTERNET异步多线程下载的源码 ( 2006-10-12 16:36 )
// 主线程工作流程
//创建下载子线程
m_hMainThread = ::CreateThread(NULL,
0,
AsyncMainThread,
this,
NULL,
&m_dwMainThreadID);
//等待子线程返回消息
MSG msg;
while (1)
{
::GetMessage(&msg, m_hWnd, 0, 0);
if (msg.message == WM_ASYNCGETHTTPFILE)
{ //子线程发回消息
switch(LOWORD(msg.wParam))
{
case AGHF_FAIL:
{
MessageBox(_T("下载行动失败结束!"));
return;
}
case AGHF_SUCCESS:
MessageBox(_T("下载行动成功结束!"));
return;
case AGHF_PROCESS:
//下载进度通知
break;
case AGHF_LENGTH:
//获取下载文件尺寸通知
break;
}
}
DispatchMessage(&msg);
}
// 下载子线程工作流程
// 使用标记 INTERNET_FLAG_ASYNC 初始化 InternetOpen
m_hInternet = ::InternetOpen(m_szAgent,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
INTERNET_FLAG_ASYNC);
// 设置状态回调函数 InternetSetStatusCallback
::InternetSetStatusCallback(m_hInternet, AsyncInternetCallback);
//重置回调函数设置成功事件
::ResetEvent(m_hEvent[0]);
m_hCallbackThread = ::CreateThread(NULL,
0,
AsyncCallbackThread,
this,
NULL,
&m_dwCallbackThreadID);
//等待回调函数设置成功事件
::WaitForSingleObject(m_hEvent[0], INFINITE);
//回调函数线程的实现如下:
DWORD WINAPI CAsyncGetHttpFile::AsyncCallbackThread(LPVOID lpParameter)
{
CAsyncGetHttpFile * pObj = (CAsyncGetHttpFile*)lpParameter;
::InternetSetStatusCallback(pObj->m_hInternet, AsyncInternetCallback);
//通知子线程回调函数设置成功,子线程可以继续工作
::SetEvent(pObj->m_hEvent[0]);
//等待用户终止事件或者子线程结束事件
//子线程结束前需要设置子线程结束事件,并等待回调线程结束
::WaitForSingleObject(pObj->m_hEvent[2], INFINITE);
return 0;
}
//打断一下子线程的流程,由于回调函数和上一部分的关系如此密切,我们来看看它的实现
void CALLBACK CAsyncGetHttpFile::AsyncInternetCallback(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength)
{
CAsyncGetHttpFile * pObj = (CAsyncGetHttpFile*)dwContext;
//在我们的应用中,我们只关心下面三个状态
switch(dwInternetStatus)
{
//句柄被创建
case INTERNET_STATUS_HANDLE_CREATED:
pObj->m_hFile = (HINTERNET)(((LPINTERNET_ASYNC_RESULT)
(lpvStatusInformation))->dwResult);
break;
//句柄被关闭
case INTERNET_STATUS_HANDLE_CLOSING:
::SetEvent(pObj->m_hEvent[1]);
break;
//一个请求完成,比如一次句柄创建的请求,或者一次读数据的请求
case INTERNET_STATUS_REQUEST_COMPLETE:
if (ERROR_SUCCESS == ((LPINTERNET_ASYNC_RESULT)
(lpvStatusInformation))->dwError)
{ //设置句柄被创建事件或者读数据成功完成事件
::SetEvent(pObj->m_hEvent[0]);
}
else
{ //如果发生错误,则设置子线程退出事件
//这里也是一个陷阱,经常会忽视处理这个错误,
::SetEvent(pObj->m_hEvent[2]);
}
break;
}
}
//继续子线程的流程,使用 InternetOpenUrl 完成连接并获取下载文件头信息
//重置句柄被创建事件
::ResetEvent(m_hEvent[0]);
m_hFile = ::InternetOpenUrl(m_hInternet,
m_szUrl,
NULL,
NULL,
INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD,
(DWORD)this);
if (NULL == m_hFile)
{
if (ERROR_IO_PENDING == ::GetLastError())
{
if (WaitExitEvent())
{
return FALSE;
}
}
else
{
return FALSE;
}
}
//等我们把 WaitExitEvent 函数的实现列出在来再解释发生的一切:
BOOL CAsyncGetHttpFile::WaitExitEvent()
{
DWORD dwRet = ::WaitForMultipleObjects(3, m_hEvent, FALSE, INFINITE);
switch (dwRet)
{
//句柄被创建事件或者读数据请求成功完成事件
case WAIT_OBJECT_0:
//句柄被关闭事件
case WAIT_OBJECT_0+1:
//用户要求终止子线程事件或者发生错误事件
case WAIT_OBJECT_0+2:
break;
}
return WAIT_OBJECT_0 != dwRet;
}
//e. 使用 HttpQueryInfo 分析头信息
DWORD dwStatusSize = sizeof(m_dwStatusCode);
if (FALSE == ::HttpQueryInfo(m_hFile,
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&m_dwStatusCode,
&dwStatusSize,
NULL)) //获取返回状态码
{
return FALSE;
}
//判断状态码是不是 200
if (HTTP_STATUS_OK != m_dwStatusCode)
{
return FALSE;
}
DWORD dwLengthSize = sizeof(m_dwContentLength);
if (FALSE == ::HttpQueryInfo(m_hFile,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&m_dwContentLength,
&dwLengthSize,
NULL)) //获取返回的Content-Length
{
return FALSE;
}
...//通知主线程获取文件大小成功
//需要说明的是 HttpQueryInfo 并不进行网络操作,因此它不需要进行异步操作的处理。
//f. 使用标记 IRF_ASYNC 读数据 InternetReadFileEx
//为了向主线程报告进度,我们设置每次读数据最多 1024 字节
for (DWORD i=0; i<m_dwContentLength; )
{
INTERNET_BUFFERS i_buf = {0};
i_buf.dwStructSize = sizeof(INTERNET_BUFFERS);
i_buf.lpvBuffer = new TCHAR[1024];
i_buf.dwBufferLength = 1024;
//重置读数据事件
::ResetEvent(m_hEvent[0]);
if (FALSE == ::InternetReadFileEx(m_hFile,
&i_buf,
IRF_ASYNC,
(DWORD)this))
{
if (ERROR_IO_PENDING == ::GetLastError())
{
if (WaitExitEvent())
{
delete[] i_buf.lpvBuffer;
return FALSE;
}
}
else
{
delete[] i_buf.lpvBuffer;
return FALSE;
}
}
else
{
//在网络传输速度快,步长较小的情况下,
//InternetReadFileEx 经常会直接返回成功,
//因此要判断是否发生了用户要求终止子线程事件。
if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEvent[2], 0))
{
::ResetEvent(m_hEvent[2]);
delete[] i_buf.lpvBuffer;
return FALSE;
}
}
i += i_buf.dwBufferLength;
...//保存数据
...//通知主线程下载进度
delete[] i_buf.lpvBuffer;
}
//关闭 m_hFile
::InternetCloseHandle(m_hFile);
//等待句柄被关闭事件或者要求子线程退出事件
while (!WaitExitEvent())
{
::ResetEvent(m_hEvent[0]);
}
//设置子线程退出事件,通知回调线程退出
::SetEvent(m_hEvent[2]);
//等待回调线程安全退出
::WaitForSingleObject(m_hCallbackThread, INFINITE);
::CloseHandle(m_hCallbackThread);
//注销回调函数
::InternetSetStatusCallback(m_hInternet, NULL);
::InternetCloseHandle(m_hInternet);
...//通知主线程子线程成功或者失败退出
分享到:
相关推荐
线程池是一种多线程编程的设计模式,它预先创建了一组线程,当有任务需要执行时,线程池会分配一个空闲线程来执行任务,而不是每次任务到来时都创建新的线程。这可以减少线程的创建和销毁带来的开销,提高系统效率。...
标题 "VC++源码保存网页为MHT文件(包含图片及其它资源)" 描述了如何使用Microsoft Visual C++(VC++)编程语言来实现一个功能,即抓取网页内容并将其保存为单一文件的MHT(MHTML,Multipurpose Internet Mail ...
FTP、HTTP 多线程断点续传下载文件 源码 如题。 gdiplus应用实例 如题,自绘控件的实现。 gdiplus应用实例2 如题,自绘控件的实现。 GetFileVersion 这个例子就是查询任何可执行文件的版本信息并且 C++builder 和...
【描述】提到的是"极速",这暗示了该FTP客户端可能实现了高效的文件传输,可能采用了多线程技术、异步I/O或者缓存策略来提升速度。在C++中,这通常涉及到Windows API的套接字编程,如WSAStartup、connect、send、...
8. **多线程编程**:在服务器端,为了同时处理多个客户端连接,可能会引入多线程概念,使用`CreateThread`创建新线程来处理每个新的连接。 9. **异步I/O**:了解IOCP(I/O完成端口)的概念,它是Windows上进行高...
6. **多线程处理**:在服务器端,为了处理多个并发连接,通常需要使用多线程技术,每个新连接创建一个新的线程进行处理,或者使用IOCP等异步I/O模型,避免阻塞主线程。 7. **异常处理**:在网络通信中,错误处理...
- **多线程处理**:为了同时处理多个客户端的连接请求,服务器通常会为每个新连接创建一个新的线程或使用异步I/O模型。 - **并发连接管理**:服务器需要维护一个连接列表,记录所有已建立连接的客户端,以便进行...
**IOCP(I/O Completion Port)是Windows操作系统中的一种高效I/O模型,它在多线程环境下用于处理大量并发I/O操作。IOCP的核心在于将I/O操作与通知机制分离,使得系统能以非阻塞的方式处理I/O请求,极大地提高了...
3. **多线程编程**:在网络编程中,多线程可以提高并发处理能力,例如,一个线程用于接收客户端连接,另一个线程负责处理数据传输。 4. **异步I/O**:在VC++6.0中,可以使用异步套接字函数,如WSAAsyncSelect或...
本文将详细解析"VC 快速查找局域网内所有机器的程序源码"这一主题,主要关注如何利用多线程技术和网络扫描技术来实现这一功能。 首先,"VC"在这里指的是Visual C++,微软开发的一款集成开发环境,支持C++编程语言。...
在Windows平台上进行网络与通信程序设计,涉及到许多关键知识点,主要涵盖了网络协议、API调用、多线程编程以及数据传输等。以下是对这些领域的详细解释: 1. **网络协议**:网络通信的基础是各种网络协议,如TCP/...
这涉及到网络编程、多线程、异步I/O等知识。 首先,我们要理解Ping命令的工作原理。它基于ICMP(Internet Control Message Protocol,互联网控制消息协议)的回显请求和应答机制。在Windows环境下,我们可以调用...
C++可以利用多线程或多进程模型来实现并发,或者使用异步I/O模型如boost.asio库来提高性能。 5. **状态管理和会话**:服务器需要跟踪每个用户的状态(如是否在线,所在的频道等),这通常通过维护一个用户和频道的...
Win32多线程应用 线程COM组件 自动化与IDispatch 用VC++实现IDispatch ATL与自动化 Automation数据类型 再谈类型库 C++自动化客户机 VB自动化客户机 小结 第3章 用VB建立并使用COM服务器 选择COM...
7.3 VC++对多线程网络编程的支持 192 7.3.1 MFC支持的两种线程 192 7.3.2 创建MFC的工作线程 193 7.3.3 创建并启动用户界面线程 195 7.3.4 终止线程 198 7.4 多线程FTP客户端实例 200 7.4.1 编写线程...
在VC++中,可以使用`CreateThread`或者`async`关键字来实现多线程或异步操作。 7. **文件I/O**:在接收端,接收的数据需要写入到本地文件中。VC++提供了标准库`fstream`来处理文件的读写操作,如`ofstream`用于写...
3. 多线程处理:为了实现异步通信和并行处理,可能会用到多线程技术。 4. 用户界面更新:当收到新消息或文件时,UI需要实时更新以显示这些信息。 通过分析和学习这个项目,你可以掌握网络编程中的基本原理和技巧,...
15.3 实例62:创建VC++宏 350 15.4 实例63:使用函数地址 351 15.5 实例64:二进制字符串 352 15.6 实例65:重新启动计算机 356 15.7 实例66:获得可用磁盘空间 357 15.8 实例67:闪烁窗口和文本 358
- **性能优化**:如果需要频繁进行ping操作,可以考虑使用多线程或者异步IO来提高效率。 - **结果解析**:收到ICMP回显应答后,需要解析报文以获取如往返时间、数据包大小等信息。 总的来说,实现VC++的ping功能...
它们允许程序在一个线程中等待多个I/O操作的完成。 3. **非阻塞I/O**:避免因等待I/O操作完成而阻塞主线程,提高系统吞吐量。 4. **异步I/O**:如Windows的`OVERLAPPED`结构和`Begin/EndSend/Receive`,在后台处理I/...