目录
前天用Qt做了一个Http下载工具,但是使用的是Qt的ApI进行开发。所以顺便用纯c++撸了一个,造几个轮子试试效果。
目前基本实现主要功能,但是暂时没有提供断点续传和Https的url下载。只支持对Http的url进行下载。
一、gitHub地址
二、功能
可以输入Http的url进行在线下载。
三、目前存在的问题
暂时没有提供对Https的url下载。
四、界面效果
五、主要代码
解析url的ip地址:
void Http::getTcpConfig(const std::string &url)
{
char domain[100] = { 0 };
char target[100] = { 0 };
char port[10] = { 0 };
char Ip[20] = { 0 };
parseUrl(m_url, domain, target, port); //解析url
getIp(domain, Ip); //获取ip
m_ip = Ip;
m_port = port;
m_target = target;
std::cout << "m_ip=" << m_ip << std::endl;
std::cout << "m_port=" << m_port << std::endl;
}
发出get请求:
void Http::getFileRequest()
{
getTcpConfig(m_url);
std::cout << "start request......................." << endl;
if (m_tcp.tcpIsOpen()) //如果是连接状态 关闭重新连接
{
m_tcp.tcpClose();
}
if (!m_tcp.tcpConnect(m_ip, m_port))
{
std::cout << "网络连接失败!" << endl;
return;
}
//接收响应头
char recvBuf[3096] = { 0 };
std::stringstream request;
request << "GET " << m_url << " HTTP/1.1\r\n";
request << "Host: " << m_ip << ":" << m_port << "\r\n";
request << "Connection:close\r\n";
request << "\r\n";
//std::cout << "request = " << request.str().c_str() << std::endl;
//发送请求头
int ret = m_tcp.tcpWrite(request.str().c_str(), sizeof(request));
if (-1 == ret)
{
m_tcp.tcpClose();
return;
}
else if (sizeof(request) == ret)
{
int ret = m_tcp.tcpRead(recvBuf, sizeof(recvBuf));
if (-1 == ret)
{
m_tcp.tcpClose();
return;
}
}
//std::cout << "recvBuf = " << recvBuf << std::endl;
if (std::string(recvBuf).empty())
{
std::cout << "网络异常!"<< std::endl;
return;
}
std::string responStr(recvBuf);
int position = responStr.find("\r\n\r\n");
if (position != -1)
{
position = position + 4;
memset(m_firstBuf, 0, sizeof(m_firstBuf));
m_fRecvByte = 0;
for (int i = position; i < sizeof(recvBuf) / sizeof(char); i++)
{
m_firstBuf[m_fRecvByte++] = recvBuf[i];
}
if (std::string(m_firstBuf).empty())
{
m_fRecvByte = 0;
}
}
//获取返回的状态码
int code = 0;
//返回字符串recvBuf中第一次出现子串HTTP/的地址
char *strPos = strstr(recvBuf, "HTTP/");
if (strPos)
{
sscanf(strPos, "%*s %d", &code);
}
strPos = strstr(recvBuf, "Content-Length");
if (strPos)
{
sscanf(strPos, "%*s %d", &m_fileLength);
}
if (code == 200) //直接下载
{
downloadFile(m_fileName);
}
else if (code == 302) //重定向
{
//获取转调地址
strPos = strstr(recvBuf, "Location");
std::string newUrl = std::string(strPos);
int pos = newUrl.find_first_of(":") + 2;
newUrl = newUrl.substr(pos, newUrl.find("\r\n") - pos);
setUrl(newUrl);
getFileRequest();
}
else
{
std::cout << "网络错误 " << code <<endl;
return;
}
}
进行下载:
void Http::downloadFile(const std::string &m_path)
{
std::cout << "start download......................." << endl;
if (m_bkptResume) //是否打开断点续传
{
std::stringstream request;
request << "GET " << m_url << " HTTP/1.1\r\n";
request << "Host:" << m_ip << ":" << m_port << "\r\n";
request << "Range: bytes=" << m_currentDownByte << "-\r\n";
request << "Connection:close\r\n";
request << "\r\n";
//std::cout << "request = " << request.str().c_str() << std::endl;
int ret = m_tcp.tcpWrite(request.str().c_str(), sizeof(request));
if (-1 == ret)
{
m_tcp.tcpClose();
return;
}
}
//创建文件
//FILE *fp = NULL;
//fp = fopen(m_fileName.c_str(), "wb");
m_fileName = m_url.substr(m_url.find_last_of("/") + 1, m_url.size());
m_file.open(m_path, std::ios::out
| std::ios::trunc | std::ios::binary); //写入
int bytes = 0;
int total = m_fileLength / (1024 * 1024);
const int wBufLength = 1024 * 1024 * 2; //2M
//char *writeBuf = (char*)malloc(sizeof(char)*length);
m_writeBuf = new char[wBufLength];
int lastCur = 0;
if (m_fRecvByte != 0)
{
m_file.write(m_firstBuf, m_fRecvByte);
bytes = bytes + m_fRecvByte;
}
while (true)
{
memset(m_writeBuf, 0, wBufLength);
int ret = m_tcp.tcpRead(m_writeBuf, wBufLength);
if (ret == SOCKET_ERROR)
{
std::cout << m_path << "下载错误" << std::endl;
break;
}
else if (ret == 0)
{
std::cout <<"网络中断,请重新下载!" << std::endl;
break;
}
//写入文件
//fwrite(writeBuf, ret, 1, fp);
m_file.write(m_writeBuf, ret);
bytes += ret;
int cur = bytes / (1024);
if (cur == 0)
{
std::cout << cur << "k" << "/" << total << "M" << std::endl;
}
else if (cur != lastCur)
{
lastCur = cur;
std::cout << cur << "k" << "/" << total << "M" << std::endl;
}
if (m_fileLength == bytes)
{
std::cout << m_path << "下载完毕" << std::endl;
break;
}
}
//free(writeBuf);
delete[] m_writeBuf;
m_writeBuf = NULL;
//fclose(fp);
m_tcp.tcpClose();
m_file.close();
}
tcp初始化:
bool Tcp::tcpConnect(const std::string ip, const std::string port)
{
WORD word = MAKEWORD(2, 2);
WSADATA ws;
if (WSAStartup(word, &ws) != 0)
{
return false;
}
m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (m_sockfd == INVALID_SOCKET)
{
perror("m_sockfd:");
return false;
}
memset(&m_clientAddr, 0, sizeof(m_clientAddr));
m_clientAddr.sin_family = AF_INET;
m_clientAddr.sin_port = htons(std::atoi(port.c_str()));
inet_pton(AF_INET, ip.c_str(), &m_clientAddr.sin_addr);
if (INVALID_SOCKET == connect(m_sockfd, (sockaddr*)&m_clientAddr, sizeof(m_clientAddr)))
{
perror("connect:");
return false;
}
std::cout << "connect successful..." << std::endl;
return true;
}