目錄
前天用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;
}