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 = -;
status_message.clear();
header.clear();
content_type.clear();
modify_time.clear();
content_length = ;
total_length = ;
offset = ;
body.clear();
}
}; struct DownloadInfo
{
DownloadInfo()
{
id = ;
url.clear();
filename.clear();
md5.clear();
writesize = ;
continued = false;
lasterr = ;
trycount = ;
}
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 ;
} // 获取文件
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 != -)
{
szService = szHost.substr(i+);
szIp = szHost.substr(, 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 = ;
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(), 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(, 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(, 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(, 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(, tmp.find('-')).c_str());
int ipos = tmp.find('/');
int ivalue = ;
if (ipos != std::string::npos)
{
ivalue = atoi(tmp.substr(ipos+).c_str());
}
if (ivalue)
result.total_length = ivalue;
}
strLine.clear();
std::getline(response_stream, strLine);
} if ( result.http_version.substr(, ) != "HTTP/")
{
std::cout << "Invalid response\n";
return false;
}
if (result.status_code != && result.status_code != )
{
std::cout << "Response returned with status code "
<< result.status_code << "\n";
return false;
} packetString.erase(, nEndHeader + ); return true;
} // **************************************************************
// 获取临时文件大小
// **************************************************************
int GetTempFileRange( const std::string& fn )
{
int rangeStart = ;
std::ifstream ifs;
ifs.open(fn, std::ios_base::in | std::ios_base::binary );
if (ifs.is_open()) {
ifs.seekg(, 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 = ;
} 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断点续传的更多相关文章
- boost强分类器的实现
boost.cpp文件下: bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator, int _numSampl ...
- HTML5实现文件断点续传
HTML5的FILE api,有一个slice方法,可以将BLOB对象进行分割.前端通过FileList对象获取到相应的文件,按照指定的分割方式将大文件分段,然后一段一段地传给后端,后端再按顺序一段段 ...
- Boost信号/槽signals2
信号槽是Qt框架中一个重要的部分,主要用来解耦一组互相协作的类,使用起来非常方便.项目中有同事引入了第三方的信号槽机制,其实Boost本身就有信号/槽,而且Boost的模块相对来说更稳定. signa ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- 玩转Windows服务系列——使用Boost.Application快速构建Windows服务
玩转Windows服务系列——创建Windows服务一文中,介绍了如何快速使用VS构建一个Windows服务.Debug.Release版本的注册和卸载,及其原理和服务运行.停止流程浅析分别介绍了Wi ...
- (实例篇)PHP实现HTTP断点续传的方法
PHP实现HTTP断点续传的方法. <?php /** * PHP-HTTP断点续传实现 * @param string $path: 文件所在路径 * @param string $file: ...
- boost::function的用法
本片文章主要介绍boost::function的用法. boost::function 就是一个函数的包装器(function wrapper),用来定义函数对象. 1. 介绍 Boost.Func ...
- C# 文件下载之断点续传
注意,本文所说的断点续传特指 HTTP 协议中的断点续传.本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo. 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息.我 ...
- Boost条件变量condition_variable_any
Boost条件变量可以用来实现线程同步,它必须与互斥量配合使用.使用条件变量实现生产者消费者的简单例子如下,需要注意的是cond_put.wait(lock)是在等待条件满足.如果条件不满足,则释放锁 ...
随机推荐
- 面向对象【林老师版】:面向过程vs面向对象(一)
一.面向过程 1.引子 面向过程:核心是过程二字,过程指的是解决问题的步骤,设计一条流水线,机械式的思维方式优点:复杂的问题流程化,进而简单化缺点:可扩展性差 2.验证代码 import json i ...
- SpringBoot笔记十三:引入webjar资源和国际化处理
目录 什么是webjar 怎么使用webjar 国际化 新建国际化配置文件 配置配置文件 使用配置文件 我们先来看一个html,带有css的,我们就以这个为准来讲解. 资源可以去我网盘下载 链接:ht ...
- Spring Boot笔记七:扩展Spring MVC
新建一个类,继承WebMvcConfigurerAdapter package com.vae.springboot.config; import org.springframework.contex ...
- 5、JPA-映射-单向多对一
多个订单对应一个用户 实体类 Customer package com.jpa.yingshe; import javax.persistence.*; @Table(name = "JPA ...
- js静态方法与实例方法定义,js回调方法定义
主要为了回调方法,随便把静态言法和实例方法也回顾一下. <script type="text/javascript"> var fun = { //下面是静态方法(第一 ...
- idea中加入tomcat
File—>Setting—>Build,Execution,Deployment—->Application Servers—>”+”这里添加了之后Edit Configur ...
- 计算机网络--HTTP协议
TCP/IP协议 互联网构建的初衷是信息的共享.在信息的传递过程中,计算机不可避免的需要产生交流.就像我们与别人交谈需要懂得对方的语言才能明白对方表达的意思一样,计算机的交流也需要一个约束了,称之为协 ...
- Newtonsoft.Json序列化Enum类型
[JsonConverter(typeof(StringEnumConverter))] public StringAlignment TextAlign { get => textAlign; ...
- C# using 的用法
Ø 前言 说起 C# using 语句,想必大家都不陌生,它是 C# 中关键字之一.我们基本每天写代码都会使用到,其实也非常简单. 1. 首先,说说 using 有哪些用途 1) 用于引用其 ...
- UIBezierPath基本使用
UIBezierPath * aPath = [UIBezierPath bezierPathWithArcCenter:point radius:5 startAngle:0 endAngle:2 ...