最近用一个网上的下载类,MyDownload里面有多线程下载的部分,一开始开三个线程,偶尔会出现崩溃。下面是下载线程
UINT CHttpGet::ThreadDownLoad(void* pParam)
{
CHttpSect *pInfo=(CHttpSect*)pParam;
SOCKET hSocket;
if(pInfo->bProxyMode){
hSocket=ConnectHttpProxy(pInfo->szProxyAddr,pInfo->nProxyPort);
}
else{
hSocket=ConnectHttpNonProxy(pInfo->szHostAddr,pInfo->nHostPort);
}
if(hSocket == INVALID_SOCKET) return 1;
// 计算临时文件大小,为了断点续传
DWORD nFileSize=myfile.GetFileSizeByName(pInfo->szDesFilename);
DWORD nSectSize=(pInfo->nEnd)-(pInfo->nStart);
rdownloaded+=nFileSize;
// 此段已下载完毕.
if(nFileSize==nSectSize){
//mj
printf("文件下载成功!下载结束!\n"); //这里可以设置写信息
//mj
TRACE("文件已下载完毕!\n");
CHttpGet::m_nCount++; // 计数.
return 0;
}
FILE *fpwrite=myfile.GetFilePointer(pInfo->szDesFilename);
if(!fpwrite) return 1;
// 设置下载范围.
SendHttpHeader(hSocket,pInfo->szHostAddr,pInfo->szHttpAddr,
pInfo->szHttpFilename,pInfo->nStart+nFileSize);
// 设置文件写指针起始位置,断点续传
fseek(fpwrite,nFileSize,SEEK_SET);
DWORD nLen;
DWORD nSumLen=0;
char szBuffer[1024];
while(1)
{
if(nSumLen>=nSectSize-nFileSize) break;
nLen=recv(hSocket,szBuffer,sizeof(szBuffer),0);
//原子操作,不用同步。
rdownloaded += nLen;
if (nLen == SOCKET_ERROR){
TRACE("Read error!\n");
fclose(fpwrite);
return 1;
}
if(nLen==0) break;
nSumLen +=nLen;
TRACE("%d\n",nLen);
// 把数据写入文件.
fwrite(szBuffer,nLen,1,fpwrite);
}
fclose(fpwrite); // 关闭写文件.
closesocket(hSocket); // 关闭套接字.
CHttpGet::m_nCount++; // 计数.
return 0;
}
这段代码看来没什么问题,线程开到50的时候崩溃问题就很明显了。跟了几次都是CString 释放出错,往回找发现是在SendHttpHeader里有问题,代码:
BOOL CHttpGet::SendHttpHeader(SOCKET hSocket,CString strHostAddr,
CString strHttpAddr,CString strHttpFilename,DWORD nPos)
{
// 进行下载.
static CString sTemp;
char cTmpBuffer[1024];
// Line1: 请求的路径,版本.
sTemp.Format(L"GET %s%s HTTP/1.1\r\n",strHttpAddr,strHttpFilename);
if(!SocketSend(hSocket,sTemp)) return FALSE;
// Line2:主机.
sTemp.Format(L"Host: %s\r\n",strHostAddr);
if(!SocketSend(hSocket,sTemp)) return FALSE;
// Line3:接收的数据类型.
sTemp.Format(L"Accept: \r\n");
if(!SocketSend(hSocket,sTemp)) return FALSE;
// Line4:参考地址.
sTemp.Format(L"Referer: %s\r\n",strHttpAddr);
if(!SocketSend(hSocket,sTemp)) return FALSE;
// Line5:浏览器类型.
sTemp.Format(L"User-Agent: Mozilla/4.0 \
(compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent;)\r\n");
if(!SocketSend(hSocket,sTemp)) return FALSE;
// 续传. Range 是要下载的数据范围,对续传很重要.
sTemp.Format(L"Range: bytes=%d-\r\n",nPos);
if(!SocketSend(hSocket,sTemp)) return FALSE;
// LastLine: 空行.
sTemp.Format(L"\r\n");
if(!SocketSend(hSocket,sTemp)) return FALSE;
// 取得http头.
int i=GetHttpHeader(hSocket,cTmpBuffer);
if(!i)
{
TRACE(L"获取HTTP头出错!\n");
return 0;
}
// 如果取得的http头含有404等字样,则表示连接出问题.
sTemp=cTmpBuffer;
if(sTemp.Find(L"404")!=-1) return FALSE;
// 得到待下载文件的大小.
m_nFileLength=GetFileLength(cTmpBuffer);
// 因为TRACE()函数最大的字符串长度为255.
//TRACE(CString(cTmpBuffer).GetBuffer(200));
return TRUE;
}
看了许久才发开头那个sTemp是static,有点不解了,作者为什么要在这里加一个static,为了效率?
总之,去掉这个static崩溃问题就没再出现了。写多线程的时候不能只看函数有没有同步问题,还要看看所调用到的函数有没有调用到全局或static变量,有的话还是保护起来,不然一不注意,出现这种问题,实在不容易跟。