使用WinInet类,连接HTTP服务器,在下载大文件时,程序会未响应

sherlockcsdn_1 2015-01-14 09:48:46

DWORD WINAPI CUpdateDlg::DownloadFileFromWeb(LPVOID lParam)
{
CUpdateDlg *pDlg=(CUpdateDlg *)lParam;
pDlg->strFileURLInServer != "";
pDlg->strFileLocalFullPath != "";
CInternetSession session;
CHttpConnection* pHttpConnection = NULL;
CHttpFile* pHttpFile = NULL;
CString strServer, strObject;
INTERNET_PORT wPort;
BOOL bReturn = FALSE;

DWORD dwType;
const int nTimeOut = 2000;
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, nTimeOut); //重试之间的等待延时
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1); //重试次数
char* pszBuffer = NULL;



try
{
AfxParseURL(pDlg->strFileURLInServer, dwType, strServer, strObject, wPort);
pHttpConnection = session.GetHttpConnection(strServer, wPort);
pHttpFile = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
if(pHttpFile->SendRequest() == FALSE)
return FALSE;
DWORD dwStateCode;

pHttpFile->QueryInfoStatusCode(dwStateCode);
if(dwStateCode == HTTP_STATUS_OK)
{
HANDLE hFile = CreateFile(pDlg->strFileLocalFullPath, GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL); //创建本地文件
if(hFile == INVALID_HANDLE_VALUE)
{
pHttpFile->Close();
pHttpConnection->Close();
session.Close();
return FALSE;
}

char szInfoBuffer[1000]; //返回消息
DWORD dwFileSize = 0; //文件长度
DWORD dwInfoBufferSize = sizeof(szInfoBuffer);
BOOL bResult = FALSE;
bResult = pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,
(void*)szInfoBuffer,&dwInfoBufferSize,NULL);

dwFileSize = atoi(szInfoBuffer);
const int BUFFER_LENGTH = 1024 * 10;
pszBuffer = new char[BUFFER_LENGTH]; //读取文件的缓冲
DWORD dwWrite, dwTotalWrite;
dwWrite = dwTotalWrite = 0;
UINT nRead = pHttpFile->Read(pszBuffer, BUFFER_LENGTH); //读取服务器上数据

ofstream fileOut("d:\\TestOut.txt", ios::app);
CString sDate;
time_t curUtcTime;
struct tm *curTime;

while(nRead > 0)
{

time(&curUtcTime);
curTime = localtime(&curUtcTime);
sDate.Format("%02d:%02d:%02d", curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
fileOut << sDate << "start write" << endl;

WriteFile(hFile, pszBuffer, nRead, &dwWrite, NULL); //写到本地文件
ZeroMemory(pszBuffer, BUFFER_LENGTH);
dwTotalWrite += dwWrite;

time(&curUtcTime);
curTime = localtime(&curUtcTime);
sDate.Format("%02d:%02d:%02d", curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
fileOut << sDate << "start read" << endl;

nRead = pHttpFile->Read(pszBuffer, BUFFER_LENGTH);

pDlg->nPecent += 1000 * nRead / ((float)dwFileSize);
//m_progressDownload.SetPos((int)nPecent);
//Sleep(5);
}

pDlg->nPecent = 1000;
//GetDlgItem(CUpdateDlg.m_hWnd, uid)->SetPos((int)nPecent);
//m_progressDownload.SetPos((int)nPecent);

delete[]pszBuffer;
pszBuffer = NULL;
CloseHandle(hFile);
bReturn = TRUE;
}
}
catch(CInternetException* e)
{
TCHAR tszErrString[256];
e->GetErrorMessage(tszErrString, sizeof(tszErrString));
TRACE(_T("Download XSL error! URL: %s,Error: %s"), pDlg->strFileURLInServer, tszErrString);
e->Delete();
}
catch(...)
{
}

if(pszBuffer != NULL)
{
delete[]pszBuffer;
}
if(pHttpFile != NULL)
{
pHttpFile->Close();
delete pHttpFile;
}
if(pHttpConnection != NULL)
{
pHttpConnection->Close();
delete pHttpConnection;
}
session.Close();
return bReturn;
}

我把这个函数创建了线程,但运行下载大文件时还是会出现程序未响应这种类似阻塞现象的情况。在未响应的过程中,文件还是一直在下载,最后也能将文件下载完成。但我需要在下载过程中同时进行其他操作。请问,怎么会产生这种情况的?
...全文
160 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿先森 2015-02-01
  • 打赏
  • 举报
回复
感谢邀请。 在新线程里面,禁止使用MFC窗口类,如CDialog,CSpliderCtrl,CProgressBarCtrl等等。
sherlockcsdn_1 2015-01-15
  • 打赏
  • 举报
回复
我把问题解决了,这个函数我之前确实是单独开一个线程运行。函数本身没有问题,阻塞原因在于另一个函数是while(1)运行,由于是MFC程序,时间一长命令处理不过来,造成了阻塞现象,程序才会未响应。现在去掉了while(1)循环,程序就通畅了。多谢各位帮助,结贴。
zgl7903 2015-01-15
  • 打赏
  • 举报
回复
Sleep(0) 切换一下 给其它线程运行的机会
弱水垂钓 2015-01-15
  • 打赏
  • 举报
回复
引用 1 楼 worldy 的回复:
CUpdateDlg::DownloadFileFromWeb 应该在一个独立的线程中调用
下载文件就不要放到主线程去做,会造成消息阻塞的,所以没有响应
worldy 2015-01-14
  • 打赏
  • 举报
回复
CUpdateDlg::DownloadFileFromWeb 应该在一个独立的线程中调用
过去做网络方面的东东的候,为了试验一些SOCKET API,编写了一个演示的DEMO,可能有朋友用得到,仅在此抛砖引玉。 这个测试工程中对Socket封装的文件: Soc.h Soc.cpp 网络传输封装 SocMesWnd 异步网络传输,接收网络消息的窗体 该DEMO演示了以下技术: 1、CTCPServe、CTCPClient Tcp异步传输,含TCP客户端与TCP服务端 2、CUDPSocket Udp异步传输 & Udp组播 3、CUDPSock5 Udp Sock5传输 4、CFtp Ftp传输 设计说明: 每个传输都有以下两个方法 void SetSocketNotify( HWND hWndMsg, UINT unMsg ){m_hWndMsg = hWndMsg; m_nMsg = unMsg;}; void SetSocketNotify(SOCKET_NOTIFY pFuncMes){m_pFuncMes = pFuncMes;}; 这两个函数用来设置发生socket事件后的外部响应方式,一种是通过窗口消息进行响应,一种是通过回调函数进行响应。这两种方式都是阻塞的。 当发生网络事件后,两种方式都收到 WPARAM wParam, LPARAM lParam 这两个参数,其中wParam是NET_MSG枚举,表示网络事件,lParam是附加数据,由SetExtData函数预先设置好。 void SetBufferLen( int nLen ); 该函数是设置当socket收到数据后,接收数据的缓冲区的大小的。当收到数据事件发生,首先将数据接收在缓冲区中,然后向发部发送消息或者调用回调函数,外部模块可以在响应函数中调用的 void GetData( const BYTE ** ppucBuf, int &nLen ) 来获取接收到的数据。 对于 CTCPServe这个,有些使用上的注意点:在收到远程连接请求后自动连接客户端,当远程连接断开,也自动删除连接该远程socket的子socket。CTCPServe由于每次接受连接请求后,建立了新的子socket去连接远程客户,所以它有些方法需要输入子通道的标识来完成某些功能。该标识在接受连接请求后通过响应消息或者函数发送给外部。 比如说: int GetRemoteIP( int nID, CString& strPeerAddress, int &nPeerPort ); 这个函数用来获取远程连接的客户端的IP和端口,参数中就需要指定是哪个远程客户。 UDP传输在接收数据的将远程发送数据的主机IP和地址传送给外部。 CUDPSock5在实际使用中发现与sock5服务器连接不是很稳定,大概是我没能很好地解析sock5协议的关系。 这个DEMO在后期添加了CFtp这个,处理FTP下载。之所以使用WinInet,因为它有一个MS确认的BUG:超设置无效。这个FTP演示了FTP协议的解析过程,完成常用的FTP功能(除FTP上传外,容我有空再做,^_^)。它也是异步的。这个支持PORT和PASSIVE两种模式的FTP,
第 1章 概述 1 1.1 网络编程相关的基本概念 1 1.1.1 网络编程与进程通信 1 1.1.2 Internet中网间进程的标识 3 1.1.3 网络协议的特征 7 1.2 三网络编程 10 1.2.1 基于TCP/IP协议栈的网络编程 10 1.2.2 基于WWW应用的网络编程 10 1.2.3 基于.NET框架的Web Services网络编程 10 1.3 客户机/服务器交互模式 13 1.3.1 网络应用软件的地位和功能 13 1.3.2 客户机/服务器模式 14 1.3.3 客户机与服务器的特性 15 1.3.4 容易混淆的术语 16 1.3.5 客户机与服务器的通信过程 16 1.3.6 网络协议与C/S模式的关系 17 1.3.7 错综复杂的C/S交互 17 1.3.8 服务器如何同为多个客户机服务 18 1.3.9 标识一个特定服务 20 1.4 P2P模式 21 1.4.1 P2P技术的兴起 21 1.4.2 P2P的定义和特征 21 1.4.3 P2P的发展 22 1.4.4 P2P的关键技术 22 1.4.5 P2P系统的应用与前景 22 习题 23 第 2章 套接字网络编程基础 24 2.1 套接字网络编程接口的产生与发展 24 2.1.1 问题的提出 24 2.1.2 套接字编程接口起源于UNIX操作系统 25 2.1.3 套接字编程接口在Windows和Linux操作系统中得到继承和发展 25 2.1.4 套接字编程接口的两种实现方式 25 2.1.5 套接字通信与UNIX操作系统的输入/输出的关系 26 2.2 套接字编程的基本概念 27 2.2.1 什么是套接字 27 2.2.2 套接字的特点 28 2.2.3 套接字的应用场合 30 2.2.4 套接字使用的数据型和相关的问题 30 2.3 面向连接的套接字编程 32 2.3.1 可靠的传输控制协议 32 2.3.2 套接字的工作过程 33 2.3.3 面向连接的套接字编程实例 34 2.3.4 进程的阻塞问题和对策 40 2.4 无连接的套接字编程 43 2.4.1 高效的用户数据报协议 43 2.4.2 无连接的套接字编程的两种模式 43 2.4.3 数据报套接字的对等模式编程实例 45 2.5 原始套接字 47 2.5.1 原始套接字的创建 47 2.5.2 原始套接字的使用 48 2.5.3 原始套接字应用实例 49 习题 51 第3章 WinSock编程 53 3.1 WinSock概述 53 3.2 WinSock库函数 55 3.2.1 WinSock的注册与注销 55 3.2.2 WinSock的错误处理函数 58 3.2.3 主要的WinSock函数 61 3.2.4 WinSock的辅助函数 74 3.2.5 WinSock的信息查询函数 77 3.2.6 WSAAsyncGetXByY型的扩展函数 79 3.3 网络应用程序的运行环境 82 习题 84 第4章 MFC编程 85 4.1 MFC概述 85 4.1.1 MFC是一个编程框架 85 4.1.2 典型的MDI应用程序的构成 87 4.2 MFC和Win32 89 4.2.1 MFC对象和Windows对象的关系 89 4.2.2 几个主要的 91 4.3 CObject 95 4.3.1 CObject的定义 95 4.3.2 CObject的特性 96 4.4 消息映射的实现 98 4.5 MFC对象的创建 102 4.5.1 MFC对象的关系 102 4.5.2 MFC提供的接口 104 4.5.3 MFC对象的创建过程 104 4.6 应用程序的退出 107 习题 107 第5章 MFC WinSock的 编程 109 5.1 CAsyncSocket 110 5.1.1 使用CAsyncSocket的一般步骤 110 5.1.2 创建CAsyncSocket对象 111 5.1.3 关于CAsyncSocket可以接受并处理的消息事件 112 5.1.4 客户端套接字对象请求连接服务器端套接字对象 114 5.1.5 服务器接收客户机的连接请求 115 5.1.6 发送与接收流式数据 116 5.1.7 关闭套接字 118 5.1.8 错误处理 118 5.1.9 其他成员函数 119 5.2 CSocket 120 5.2.1 创建CSocket对象 120 5.2.2 建立连接 120 5.2.3 发送和接收数据 120 5.2.4 CSocket、CArchive和CSocketFile 121 5.2.5 关闭套接字和清除相关的对象 122 5.3 CSocket的编程模型 122 5.4 用CAsyncSocket实现聊天室程序 123 5.4.1 实现目标 123 5.4.2 创建客户端应用程序 124 5.4.3 客户端程序与消息驱动 134 5.4.4 客户端程序主要功能的代码和分析 135 5.4.5 创建服务器程序 142 5.4.6 服务器程序的流程和消息驱动 144 5.4.7 点对点交谈的服务器程序主要功能的代码和分析 145 5.5 用CSocket实现聊天室程序 151 5.5.1 聊天室程序的功能 151 5.5.2 创建聊天室的服务器程序 151 5.5.3 聊天室服务器程序的主要实现代码和分析 154 5.5.4 创建聊天室的客户端程序 162 5.5.5 聊天室客户端程序的主要实现代码和分析 163 习题 170 实验 170 第6章 WinInet编程 172 6.1 MFC WinInet 172 6.1.1 概述 172 6.1.2 MFC WinInet所包含的 173 6.1.3 使用WinInet编程的一般步骤 174 6.1.4 创建CInternetSession对象 175 6.1.5 查询或设置Internet请求选项 176 6.1.6 创建连接对象 177 6.1.7 使用文件检索 178 6.1.8 重载OnStatusCallback函数 179 6.1.9 创建并使用网络文件对象 180 6.1.10 CInternteException 183 6.2 用MFC WinInet实现FTP客户端 183 6.2.1 程序要实现的功能 183 6.2.2 创建应用程序的过程 184 习题 186 实验 187 第7章 WinSock的多线程 编程 188 7.1 WinSock为什么需要多线程编程 188 7.1.1 WinSock的两种I/O模式 188 7.1.2 两种模式的优缺点及解决方法 189 7.2 Win32操作系统下的多进程多线程机制 189 7.2.1 Win32 OS是单用户多任务的操作系统 189 7.2.2 Win32 OS是支持多线程的操作系统 190 7.2.3 多线程机制在网络编程中的应用 191 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 编写线程函数 200 7.4.2 添加事件处理函数 206 习题 208 第8章 WinSock的I/O模型 209 8.1 select模型 210 8.2 WSAAsyncSelect异步I/O模型 212 8.3 WSAEventSelect事件选择模型 216 8.4 重叠I/O模型 221 8.4.1 重叠I/O模型的优点 221 8.4.2 重叠I/O模型的基本原理 221 8.4.3 重叠I/O模型的关键函数和数据结构 222 8.4.4 使用事件通知实现重叠模型的步骤 225 8.4.5 使用完成例程实现重叠模型的步骤 227 8.5 完成端口模型 229 8.5.1 什么是完成端口模型 229 8.5.2 使用完成端口模型的方法 230 习题 238 第9章 HTTP及编程 239 9.1 HTTP 239 9.1.1 HTTP的背景 239 9.1.2 HTTP的内容 240 9.1.3 HTTP消息的一般格式 242 9.1.4 HTTP请求的格式 243 9.1.5 HTTP响应的格式 245 9.1.6 访问认证 248 9.1.7 URL编码 249 9.1.8 HTTP的应用 250 9.2 利用CHtmlView创建Web浏览器型的应用程序 250 9.2.1 CHtmlView与WebBrowser控件 250 9.2.2 CHtmlView的成员函数 251 9.2.3 创建一个Web浏览器型的应用程序的一般步骤 256 9.3 Web浏览器应用程序实例 261 9.3.1 程序实现的目标 261 9.3.2 创建实例程序 262 习题 265 实验 265 第 10章 电子邮件协议与编程 267 10.1 电子邮件系统的工作原理 267 10.1.1 电子邮件的特点 267 10.1.2 电子邮件系统的构成 267 10.1.3 电子邮件系统的实现 268 10.2 简单邮件传送协议 270 10.2.1 概述 270 10.2.2 SMTP客户机与SMTP服务器之间的话 270 10.2.3 常用的SMTP命令 271 10.2.4 常用的SMTP响应码 273 10.2.5 SMTP的话过程 274 10.2.6 使用WinSock来实现电子邮件客户机与服务器话 274 10.3 电子邮件信件结构详述 275 10.3.1 Internet文本信件的格式标准——RFC 822 275 10.3.2 信件的头部 276 10.3.3 构造和分析符合RFC 822标准的电子信件 281 10.4 MIME编码解码与发送附件 281 10.4.1 MIME概述 281 10.4.2 MIME定义的新的信头字段 282 10.4.3 MIME邮件的内容型 283 10.4.4 MIME邮件的编码方式 292 10.5 POP3与接收电子邮件 294 10.5.1 POP3 294 10.5.2 POP3的话过程 294 10.5.3 POP3话的3个状态 295 10.5.4 POP3标准命令 296 10.5.5 接收电子邮件的一般步骤 298 10.6 接收电子邮件的程序实例 299 10.6.1 实例程序的目的和实现的技术要点 299 10.6.2 创建应用程序的过程 301 10.7 发送电子邮件的程序实例 302 10.7.1 实例程序的目的和实现的技术要点 302 10.7.2 创建应用程序的过程 303 习题 305 参考文献 307
版本9.2中有什么新功能 完整的RAD Studio 10.2.3东京支持。 SFTP - 添加了新的强加密算法,修复了SSH连接问题。 为TLS 1.3做好准备 - 在官方TLS 1.3发布之后,组件将使用新协议。 实现了为SSL / TLS连接提供根证书的能力。新的SendRootCertificate属性已添加到所有客户端和服务器组件。 添加了使用唯一强加密算法的选项(禁用已知的弱加密算法,密码套件和SSL / TLS协议版本,包括RC4)。新的UseStrongCryptoAlgorithms属性在客户端和服务器组件中实现。 国际域名(IDN)支持被添加到URL解析器中,过WinInet函数被新代码替换。 CertificateStore - 添加了为给定证书加载证书链的功能。 HTTP PATCH命令已实现。 SoapMessage - 改进了消息签名和验证性能。XmlCrlfEncode和XmlCrlfDecode方法已被替换。 SMIME - 增加了新的强加密和签名算法。 SMIME - 新的Config属性允许您更改使用的加密算法和其他加密参数。通过更新版本的组件,您可以在验证和解密消息之前获取有关使用的加密算法,签名密钥长度和数字证书的信息。 更新的Encryptor组件允许您从受保护的文件中提取使用的加密算法,密钥长度和其他信息。添加了一组重载方法。 添加了IMAP4 UTF7名称编码。实现的功能允许您将国际邮箱名称与客户端和服务器组件一起使用。 IMAP4客户端 - 添加了对多个标记的SEARCH响应的支持。 IMAP4客户端 - 从TclImap4MailBoxInfo中删除了UnseenMessages属性。 更新的OAuth组件允许您在与OAUTH服务器协商刷新授权令牌并指定自定义请求字段。 BounceChecker - 更新后的组件通过使用正则表达式语法从邮件中提取所有电子邮件地址,分析邮件内容,并指示邮件是否包含送达报告。 重新命名和重新组织编码器组件的编码/解码方法,以改善界面和可用性。 下载程序,上传程序,MultiDownloader,MultiUploader,NewsChecker - URL_COMPONENTS结构已替换为TclUrlParser,实现了完整的Unicode支持。 SSH引擎 - 实现了对全局请求处理的支持。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧