现在的位置: 首页 > 综合 > 正文

遇到多线程问题,关于MyDownload

2013年08月13日 ⁄ 综合 ⁄ 共 2746字 ⁄ 字号 评论关闭

     最近用一个网上的下载类,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变量,有的话还是保护起来,不然一不注意,出现这种问题,实在不容易跟。

抱歉!评论已关闭.