1.前言
通过http下载文件比较普遍,这里简单列举两种方法.1.直接使用微软Internet系列api来实现较为简单,对windows环境依赖性较大,经过测试有少量用户无法进行正确下载 2.通过tcp模拟http文件下载,这个通用性较好
2.代码
1.Internet系列函数实现
bool downLoadFile(const TCHAR *Url, const TCHAR *ptFilePath)
{
bool bret = false;
HINTERNET hSession = InternetOpen(TEXT("RookIE/1.0"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hSession != NULL)
{
HINTERNET handle2 = InternetOpenUrl(hSession, Url, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if (handle2 != NULL)
{
byte Temp[MAXBLOCKSIZE] = {0};
ULONG Number = 1;
DWORD dwBytesWritten ;
HANDLE hFile;
if (INVALID_HANDLE_VALUE !=
(hFile = CreateFile (ptFilePath, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, 0, NULL)))
{
while (Number > 0)
{
BOOL bRet = InternetReadFile(handle2, Temp, MAXBLOCKSIZE - 1, &Number);
WriteFile (hFile, Temp, Number * sizeof (byte),
&dwBytesWritten, NULL);
}
CloseHandle(hFile);
bret = true;
}
InternetCloseHandle(handle2);
handle2 = NULL;
}
InternetCloseHandle(hSession);
hSession = NULL;
}
return bret;
}
2.通过tcp模拟http文件请求
bool downTcpFile(const std::string &strurl, const std::string &strfilepath)
{
bool bret = false;
std::string strip("");
int nport = 0;
std::string strsenddata("");
if (!strurl.empty() && !strfilepath.empty())
{
std::string strsuburl(""), strhost(""), strip(""), strport("80");
int npos = strurl.find("http://");
if (npos != -1)
strhost = strurl.substr(npos + strlen("http://"));
else
{
cout<<"ipmap.txt下载地址http非法"<<endl;
return bret;
}
npos = strhost.find("/");
if (npos != -1)
{
strsuburl = strhost.substr(npos);
strhost = strhost.substr(0, npos);
}
else
{
cout<<"ipmap.txt下载地址子域名非法"<<endl;
return bret;
}
npos = strhost.find(":");
if (npos != -1)
{
strip = strhost.substr(0, npos);
strport = strhost.substr(npos + 1);
}
else
strip = strhost;
char szbuf[1024] = {0};
sprintf(szbuf, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", strsuburl.c_str(), strhost.c_str());
INT nret;
SOCKADDR_IN addr;
SOCKET Socket;
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int nTvlen = 2000;
setsockopt(Socket,SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTvlen,sizeof(nTvlen));
setsockopt(Socket,SOL_SOCKET, SO_SNDTIMEO, (const char*)&nTvlen,sizeof(nTvlen));
if( Socket == INVALID_SOCKET )
{
closesocket(Socket);
return bret;
}
try
{
struct hostent *host;
host = gethostbyname(strip.c_str());
if (host != NULL)
{
SOCKADDR_IN SockAddr;
SockAddr.sin_port=htons(atoi(strport.c_str()));
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
closesocket(Socket);
return bret;
}
send(Socket, szbuf,strlen(szbuf), 0);
std::string strdata("");
int nrecv = 0;
do
{
char szdata[4096] = {0};
nrecv = recv(Socket, szdata, 4095, 0);
if (nrecv > 0)
{
strdata.append(szdata, nrecv);
break;
}
} while (nrecv > 0);
int npos = strdata.find("[alayun]");
if (npos != -1)
{
strdata = strdata.substr(npos);
std::fstream ffile;
ffile.open(strfilepath, std::ios_base::out);
if (ffile.is_open())
{
ffile<< strdata;
ffile.close();
}
bret = true;
}
else
cout<<strdata<<endl;
}
else
cout<<""<<endl;
closesocket(Socket);
} catch (...)
{
writelog("发送数据发生异常");
}
}
else
writelog("error in httppost");
return bret;
}
3.说明
1.在win7+vs2010(命令行程序) 上测试正常
2.参考了一些网上的资料,不再枚举,向同行致敬