使用Boost实现Http断点续传

不多说了, 自已也是一知半解的, 按虎画猫的..

慢慢学, 不要着急,

将它揉碎了, 嚼烂了, 变成自已的. .

上代码:

// testc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <fstream>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/algorithm/string.hpp>

using boost::asio::ip::tcp;

struct HttpResponse
{
public:
	explicit HttpResponse(){ clear();}
	std::string http_version;		// 版本
	unsigned int status_code;		// 状态码
	std::string status_message;	// 状态
	std::string header;					// HTTP包头
	std::string body;           // HTTP返回的内容
	std::string content_type;
	std::string modify_time;
	unsigned int content_length;
	unsigned int total_length;
	unsigned int offset;

	void clear()
	{
		http_version.clear();
		status_code = -1;
		status_message.clear();
		header.clear();
		content_type.clear();
		modify_time.clear();
		content_length = 0;
		total_length = 0;
		offset = 0;
		body.clear();
	}
};

struct DownloadInfo
{
	DownloadInfo()
	{
		id = 0;
		url.clear();
		filename.clear();
		md5.clear();
		writesize = 0;
		continued = false;
		lasterr = 0;
		trycount = 0;
	}
	int id;
	std::string url;
	std::string filename;
	std::string md5;
	int writesize;
	bool continued;
	int lasterr;
	int trycount;
};

int  GetTempFileRange( const std::string& fn );
bool GetHttpFile(const std::string& szHost, const std::string& szParam);
bool AnalyseHeader(HttpResponse& result, std::string& packetString, int nEndHeader);
bool WriteFile( const std::string& fn, int rangeStart, std::string& packetString, DownloadInfo* d_diCurrent );

std::ofstream f_ofsSave;

int _tmain(int argc, _TCHAR* argv[])
{
	std::string szHost ("192.168.1.102");
	std::string szParam("/DoDo/aishen.mp4");

	GetHttpFile(szHost, szParam);

	return 0;
}

// 获取文件
bool GetHttpFile(const std::string& szHost, const std::string& szParam)
{
	// 创建下载信息
	DownloadInfo* d_diCurrent = new DownloadInfo();
	d_diCurrent->filename = "DownLoadFile";
	d_diCurrent->continued = true;

	if(d_diCurrent->continued) {
		d_diCurrent->filename = d_diCurrent->filename+std::string(".td");
	}

	try
	{
		boost::asio::io_service io_serv;

		// Get a list of endpoints corresponding to the server name.
		std::string szService ("http");
		std::string szIp = szHost;
		int i = szHost.find(":") ;
		if (i != -1)
		{
			szService = szHost.substr(i+1);
			szIp = szHost.substr(0, i);
		}
		tcp::resolver::query query(szIp, szService);

		tcp::resolver m_resolver(io_serv);
		// 创建SOCKET
		tcp::socket s_socket(io_serv); 

		tcp::resolver::iterator endpoint_iterator = m_resolver.resolve(query), end_it;

		// Try each endpoint until we successfully establish a connection.
		tcp::resolver::iterator it = boost::asio::connect(s_socket, endpoint_iterator);

		if(it == end_it)
			return false;

		boost::asio::streambuf request;
		{
			// 封装请求HTTP GET
			std::ostream request_stream(&request);		

			request_stream << "GET " ;
			request_stream << szParam << " HTTP/1.1\r\n";
			request_stream << "Host: " << szHost << "\r\n";

			request_stream << "Accept: */*\r\n";
			request_stream << "Pragma: no-cache\r\n";
			request_stream << "Cache-Control: no-cache\r\n";
			request_stream << "Connection: close\r\n";

			// 1. 是否开启断点续传, 如是则读取临时文件长度
			int rangeStart = 0;
			if (d_diCurrent->continued) {
				rangeStart = GetTempFileRange(d_diCurrent->filename);
				if (rangeStart) {
					request_stream << "Range: bytes=" << rangeStart << "- \r\n";
				}
				request_stream << "\r\n";
			}

			boost::asio::write(s_socket, request);

			boost::asio::streambuf response;
			std::ostringstream packetStream;
			try
			{
				// Read until EOF, writing data to output as we go.
				bool hasReadHeader = false;

				boost::system::error_code error;

				HttpResponse result;
				result.body.clear();

				while (boost::asio::read(s_socket, response,
					boost::asio::transfer_at_least(1), error))
				{
					packetStream.str("");
					packetStream << &response;

					std::string packetString = packetStream.str(); 

					// 2. 是否已分析文件头
					if (!hasReadHeader)
					{
						hasReadHeader = true;
						// 取出http header
						size_t nEndHeader = packetString.find("\r\n\r\n");
						if(nEndHeader == std::string::npos)
							continue;

						if(!AnalyseHeader(result, packetString, nEndHeader)) {
							return false;
						}
					}

					// 3. 写入文件
					WriteFile(d_diCurrent->filename, rangeStart, packetString, d_diCurrent);
				}

				// 4. 关闭文件
				f_ofsSave.close();

				// 5. 文件改名
				std::string fn = "DownLoadFile.db";
				rename(d_diCurrent->filename.c_str(), fn.c_str());

				if (error != boost::asio::error::eof)
					throw boost::system::system_error(error);

			}
			catch (std::exception& e)
			{
				std::cout << "Exception: " << e.what() << "\n";
				return false;
			}
		}
	}
	catch(std::exception& e) {
		std::cout << "Exception: " << e.what() << "\n";
		return false;
	}

	return true;
}

// *****************************************************
// 分析文件头
// *****************************************************
bool AnalyseHeader(HttpResponse& result, std::string& packetString, int nEndHeader)
{
	result.header = packetString.substr(0, nEndHeader);

	// Check that response is OK.
	std::istringstream response_stream(result.header);
	response_stream >> result.http_version;
	response_stream >> result.status_code;

	std::string strLine;
	std::getline(response_stream, strLine);
	while (!strLine.empty())
	{
		if (strLine.find("Content-Type:") != std::string::npos)
		{
			result.content_type = strLine.substr(strlen("Content-Type:"));
			result.content_type.erase(0, result.content_type.find_first_not_of(" "));
		}
		if (strLine.find("Content-Length:") != std::string::npos)
		{
			result.content_length = atoi(strLine.substr(strlen("Content-Length:")).c_str());
			result.total_length = result.content_length;
		}
		if (strLine.find("Last-Modified:") != std::string::npos)
		{
			result.modify_time = strLine.substr(strlen("Last-Modified:"));
			result.modify_time.erase(0, result.modify_time.find_first_not_of(" "));
		}
		if (strLine.find("Content-Range: bytes") != std::string::npos)
		{
			std::string tmp = strLine.substr(strlen("Content-Range: bytes"));
			result.offset = atoi(tmp.substr(0, tmp.find('-')).c_str());
			int ipos = tmp.find('/');
			int ivalue = 0;
			if (ipos != std::string::npos)
			{
				ivalue = atoi(tmp.substr(ipos+1).c_str());
			}
			if (ivalue)
				result.total_length = ivalue;
		}
		strLine.clear();
		std::getline(response_stream, strLine);
	}

	if ( result.http_version.substr(0, 5) != "HTTP/")
	{
		std::cout << "Invalid response\n";
		return false;
	}
	if (result.status_code != 200 && result.status_code != 206)
	{
		std::cout << "Response returned with status code "
			<< result.status_code << "\n";
		return false;
	}

	packetString.erase(0, nEndHeader + 4);

	return true;
}

// **************************************************************
// 获取临时文件大小
// **************************************************************
int GetTempFileRange( const std::string& fn )
{
	int rangeStart = 0;
	std::ifstream ifs;
	ifs.open(fn, std::ios_base::in | std::ios_base::binary );
	if (ifs.is_open()) {
		ifs.seekg(0, std::ios::end);
		rangeStart = ifs.tellg();
	}
	ifs.close();

	return rangeStart;
}

// **************************************************************
// 写入文件
// **************************************************************
bool WriteFile( const std::string& fn, int rangeStart, std::string& packetString, DownloadInfo* d_diCurrent )
{
	if (!f_ofsSave.is_open())
	{
		if (d_diCurrent->continued)
		{
			f_ofsSave.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::app );
			if (f_ofsSave.is_open())
			{
				f_ofsSave.seekp(rangeStart);
				d_diCurrent->writesize += rangeStart;
				//int range = f_ofsSave.tellp();
			}
		}
		else
		{
			f_ofsSave.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc );
		}

		if (!f_ofsSave.is_open())
		{
			return false;
		}

		d_diCurrent->writesize = 0;
	}

	try {
		f_ofsSave.write(packetString.c_str(), packetString.length());
		d_diCurrent->writesize += packetString.length();
	}
	catch (std::exception &e)
	{
		return false;
	}

	std::cout << " write size = "<<d_diCurrent->writesize<<"\n";

	return true;
}

使用Boost实现Http断点续传,布布扣,bubuko.com

时间: 2024-08-14 17:19:19

使用Boost实现Http断点续传的相关文章

boost 实现http断点续传

// testc.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <fstream> #include <boost/asio.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/algorithm/string.hpp> using boost::a

linux下wget命令,支持断点续传,ftp、http、https等协议

转载的地址:http://blog.163.com/[email protected]/blog/static/32097310201171833420905/ 今天操作远端机器的时候发现少一个安装包, 需要传到对方的机器上,还能使用通过的老办法,直接SSH连上去了,发现传的很慢, 只有40K的样子, 看时间还需要二个多小时就有点受不了了.想想有一台FTP服务器上有这个文件,可以直接从FTP服务器上下载不就得了.本想电话指导着操作,但想到对面的操作能力,不禁心里又打起鼓来. 使用google搜了

mac下编译 boost编译工具b2

cd boost_1_64_0/tools/build ./bootstrap.sh --with-toolset=gcc 输出: -n Bootstrapping the build engine with toolset gcc... engine/bin.macosxx86_64/b2 Bootstrapping is done. To build and install, run: ./b2 install --prefix=<DIR> ./b2 install --prefix=/u

10 C++ Boost ASIO网路通信库 TCP/UDP,HTTP

  tcp 同步服务器,显示服务器端时间 tcp 同步服务器,提供多种选择 多线程的tcp 同步服务器 tcp 同步客户端 boost 域名地址解析 tcp异步服务器 tcp 异步客户端 UDP同步服务器 UDP同步客户端 UDP异步服务器 UDP异步客户端 HTTP同步客户端 HTTP异步客户端 同步实验: 异步实验 多线程异步实验 tcp 同步服务器,显示服务器端时间 [email protected]:~/boost$ cat main.cpp  #include <ctime> #in

Boost学习笔记(三) progress_timer

progress_timer也是一个计时器,它继承自timer,会在析构时自动输出时间,省去timer手动调用elapsed()的工作,是一个用于自动计时相当方便的小工具. #include <boost\timer.hpp> #include <boost\progress.hpp> #include <iostream> using namespace boost; using namespace std; int main() { boost::progress_

Boost练习程序(multi_index_container)

代码来自:http://blog.csdn.net/whuqin/article/details/8482547 该容器能实现多列索引,挺好. #include <string> #include <iostream> #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered

win7 codeblock在调用boost::asio中遇到的错误———解决办法

错误一:    undefined reference to `boost::system::generic_category()'         undefined reference to `boost::system::generic_category()'         undefined reference to `boost::system::system_category()' 解决办法:在boost的system库的error_code.hpp源代码中添加: #define

boost智能指针使用

#include <iostream> #include <tr1/memory> #include <boost/scoped_ptr.hpp> //scoped_ptr还不属于tr1 #include <boost/scoped_array.hpp> //scored_array也不属于tr1 #include <boost/shared_array.hpp> //shared_array也不属于tr1 class CTest { publi

智能指针tr1::shared_ptr、boost::shared_ptr使用

对于tr1::shared_ptr在安装vs同时会自带安装,但是版本较低的不存在.而boost作为tr1的实现品,包含 "Algorithms Broken Compiler Workarounds Concurrent Programming Containers Correctness and Testing Data Structures Domain Specific Function Objects and Higher-order Programming Generic Progra