1 需求 获取http server的图片
用http协议获取server上的图片,前面有文章使用socket直接获取http内容之一,链接如下:
简洁的c++http协议获取内容一
使用简洁的方式目的是为了减少使用其他库来放入程序,如果我们已经使用了boost的asio库,那么至少我们可以直接使用boost来获取图片。如果没有使用,读者可以看上一篇文章。
2 使用boost的asio 来获取图片,读者可以自行修正成异步获取,这里是同步获取
boost的asio有很多好处,不同于其他封装,可以使用同步,异步,协程方式获取,这里使用的是同步,调用一个函数返回图片内存和图片大小,当然,读者可以修改,这里只是一个demo。代码的原理如下:
- 发送http 头部信息
- 等待接收数据,获取http头部
- 解析头部信息,获取Content-Length
- 准备内存,接收数据
- 返回数据
show me the code
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using std::string;
//这里直接搜索http的头部字符串
int split_httphead(const std::string str,std::string &k,std::string &v)
{
size_t pos = -1;
for (size_t i = 0; i < str.size(); i++)
{
if (str[i] == ':')
{
pos = i;
break;
}
}
if (pos != -1)
{
k = str.substr(0, pos);
while (str[pos++] == ' ');
v = str.substr(pos + 1);
v.pop_back();//remove \r
}
return pos;
}
uint8_t *get(const string& host, const string& port, const string& page,size_t &length)
{
length =0;
boost::asio::io_service io_service;
if (io_service.stopped())
io_service.reset();
// 从dns取得域名下的所有ip
tcp::resolver resolver(io_service);
tcp::resolver::query query(host, port);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << page << " HTTP/1.0\r\n";
request_stream << "Host: " << host << "\r\n";
request_stream << "Accept: */*\r\n";
//
request_stream << "User-Agent: MST browser/1.1.1\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout<<"Invalid response";
return NULL;
}
if (status_code != 200)
{
std::cout<<"Response status code != 200 ";
return NULL;
}
uint32_t len = 0;
std::string header;
std::vector<string> headers;
while (std::getline(response_stream, header) && header != "\r")
headers.push_back(header);
for (size_t i = 0; i < headers.size(); i++)
{
//std::cout << headers[i] << std::endl;
std::string k, v;
if (split_httphead(headers[i], k, v) > 0)
{
std::cout << k << "->" << v << std::endl;
if (k.compare("Content-Length") == 0)
{
len = std::atoi(v.c_str());
}
}
}
#if 1 //修改成为以下这种方式
boost::system::error_code error;
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error));
//string reponse_data;
//响应有数据
if (response.size())
{
std::cout << response.size();
uint8_t * buffer = new uint8_t[len];
response.sgetn((char*)buffer, len);
length = len;
return buffer;
//std::istream response_stream(&response);
//std::istreambuf_iterator<char> eos;
//reponse_data = string(std::istreambuf_iterator<char>(response_stream), eos);
}
if (error != boost::asio::error::eof)
{
//reponse_data = error.message();
return NULL;
}
#if 0
// 读取所有剩下的数据作为包体
boost::system::error_code error;
uint8_t * data = NULL;
if (len > 0)
{
data = new uint8_t[len];
boost::asio::read(socket, boost::asio::buffer(data, len), error);
if (error == boost::asio::error::eof)
{
length = len;
return data;
}
else
{
std::cout << error.message();
length = 0;
delete[]data;
data = NULL;
return NULL;
/*boost::asio::async_read(socket, boost::asio::buffer(v_data, len),
[this, self](const std::error_code &ec, size_t len) {
std::cout << "receive " << len << std::endl;
});*/
}
}
else
{
std::cout << "not find the content-length" << std::endl;
length = 0;
return NULL;
}
#endif
}
int main(int argc, char* argv[])
{
string host = "192.168.0.240";
string port = "3001";
string page = "/file/plan_file/img1.png";
//http://192.168.0.129/cache/convert/58d17d693f85fb3708f95da032e4342e/0.png
//http://192.168.0.240:3001/file/plan_file/img.png
string reponse_data;
size_t length;
uint8_t * data = get(host, port, page, length);
if (data != NULL)
{
std::cout << "get the image len is :" <<length<< std::endl;
delete[]data;
}
else
{
std::cout << "not get the image" << std::endl;
}
return 0;
}