基於原生c++代碼實現的Http下載程序

目錄

一、gitHub地址

二、功能

三、目前存在的問題

四、界面效果

五、主要代碼


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

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章