简洁的c++http协议获取内容(二)--获取服务器图片

1 需求 获取http server的图片

用http协议获取server上的图片,前面有文章使用socket直接获取http内容之一,链接如下:
简洁的c++http协议获取内容一
使用简洁的方式目的是为了减少使用其他库来放入程序,如果我们已经使用了boost的asio库,那么至少我们可以直接使用boost来获取图片。如果没有使用,读者可以看上一篇文章。

2 使用boost的asio 来获取图片,读者可以自行修正成异步获取,这里是同步获取

boost的asio有很多好处,不同于其他封装,可以使用同步,异步,协程方式获取,这里使用的是同步,调用一个函数返回图片内存和图片大小,当然,读者可以修改,这里只是一个demo。代码的原理如下:

  1. 发送http 头部信息
  2. 等待接收数据,获取http头部
  3. 解析头部信息,获取Content-Length
  4. 准备内存,接收数据
  5. 返回数据

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;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qianbo_insist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值