Http请求通过线程添加超时处理

解决问题:

1.通过boost库asio去发送Http post请求,本文采用官方的同步调用方式(http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/http/client/sync_client.cpp

2.因为socket读写可能会堵塞,如Server迟迟没有返回,此时需要设置timeout来中断本次处理,

 因而采用新建线程HttpClient::wait_timeout来解决此问题,

3.LOGGER_DEBUG输出请自行修改

4.调用方式如下:

std::string ip ="172.16.17.58";

std::string port = "8181";

std::string path = "/login/";

std::string http_req_body = "user_name=tx02&password=e10adc3949ba59abbe56e057f20f8888";

HttpClient client(ip, port, path, http_req_body);

if(0 == client.post())

{

std::string response = client.getResponse()

......

}


代码如下:

1. HttpClient.h

#ifndef _HTTPCLIENT_H_
#define _HTTPCLIENT_H_
#include <string>
#include "logger.h"
#include <boost/asio.hpp>
#include "boost/thread/mutex.hpp"
#include "boost/thread/condition_variable.hpp"
using boost::asio::ip::tcp;
class HttpClient
{
public:
	HttpClient(const std::string&ip, const std::string&port);
	HttpClient(const std::string&ip, const std::string&port, const std::string&path,const std::string&content);
	~HttpClient(void);
public:
	std::string setUrl(const std::string& path){path_ = path;};
	std::string setContent(const std::string& content){content_ = content;};
	std::string getResponse(){return body_;};
	int post();

private:
	std::string getValidJson(const std::string& response);
	void wait_timeout(tcp::socket *socket);
	void incrementAliveThread();
	void decrementAliveThread();
	void interruptThread();

private:
	std::string ip_;
	std::string port_;
	std::string path_;
	std::string content_;

	std::string body_;
	boost::mutex mu_; 
	boost::condition_variable_any cond_; 

	int alive_thread_count;

};
#endif // _HTTPCLIENT_H_
2. HttpClient.cpp

#include "httpclient.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/thread.hpp> 
#include <boost/bind.hpp>
#include <boost/function/function0.hpp>


HttpClient::HttpClient(const std::string&ip, const std::string&port):
ip_(ip),port_(port)
{
	alive_thread_count = 0;
}

HttpClient::HttpClient(const std::string&ip, const std::string&port, const std::string&path,const std::string&content):
ip_(ip),port_(port),path_(path),content_(content)
{
	alive_thread_count = 0;
}

HttpClient::~HttpClient(void)
{
}

void HttpClient::incrementAliveThread()
{
	boost::mutex::scoped_lock lock(mu_); 
	alive_thread_count++;	
	LOGGER_DEBUG("incrementAliveThread " << alive_thread_count);
}
void HttpClient::decrementAliveThread()
{
	boost::mutex::scoped_lock lock(mu_); 
	alive_thread_count--;	
	LOGGER_DEBUG("decrementAliveThread " << alive_thread_count);
}
void HttpClient::interruptThread()
{
	while(alive_thread_count)
	{
		LOGGER_DEBUG("Force the thread finish");
		boost::mutex::scoped_lock lock(mu_); 
		cond_.notify_all(); 
		boost::this_thread::sleep(boost::posix_time::milliseconds(5)); 
	}

}
void HttpClient::wait_timeout(tcp::socket *socket) 
{ 
	{
		boost::mutex::scoped_lock lock(mu_); 
		if (cond_.timed_wait(lock, boost::get_system_time() + boost::posix_time::seconds(10)))   
		{  
			LOGGER_DEBUG("recieved notification!");  
		} else {  
			LOGGER_ERROR("timeout, didn't recieve notification!");   
			socket->close();
		}
	}
	decrementAliveThread();
}

int HttpClient::post()
{
	try
	{
		int ret = 0;
		alive_thread_count = 0;
		// Get a list of endpoints corresponding to the server name.
		boost::asio::io_service io_service;
		tcp::resolver resolver(io_service);
		tcp::resolver::query query(ip_, port_);
		tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

		// Try each endpoint until we successfully establish a connection.
		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 << "POST " << path_  << " HTTP/1.1\r\n";
		request_stream << "Host: " << ip_ << "\r\n";
		request_stream << "Accept: */*\r\n";
		request_stream << "Connection: close\r\n";			
		request_stream << "Content-Type: application/json; charset=utf-8 \r\n";
		request_stream << "Content-Length: " << content_.length() << "\r\n";
		request_stream  << "\r\n";
		request_stream  << content_;
		
		// Send the request.
		boost::function0<void> f = boost::bind(&HttpClient::wait_timeout,this, &socket); 
		incrementAliveThread();
	    boost::thread t(f); 
		boost::asio::write(socket, request);
		// Read the response status line. The response streambuf will automatically
		// grow to accommodate the entire line. The growth may be limited by passing
		// a maximum size to the streambuf constructor.
		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/")
		{
			interruptThread();
			LOGGER_ERROR("Invalid response" );
			return 1;
		}

		if (status_code != 200)
		{
			interruptThread();
			LOGGER_ERROR("Response returned with status code " << status_code);
			return 2;
		}

		// Read the response headers, which are terminated by a blank line.
		boost::asio::read_until(socket, response, "\r\n\r\n");
		// Process the response headers.
		std::string header;
		while (std::getline(response_stream, header) && header != "\r")
		{
			LOGGER_DEBUG(header);
		}

		// Write whatever content we already have to output.
		std::ostringstream ss;
		if (response.size() > 0)
		{
			ss << &response;
			body_ = ss.str();
		}

		// Read until EOF, writing data to output as we go.
		boost::system::error_code error;
		while (boost::asio::read(socket, response,
			boost::asio::transfer_at_least(1), error))
		{	
			ss << &response;
			body_ += ss.str();
		}

		{
			boost::mutex::scoped_lock lock(mu_); 
			cond_.notify_all();
		}
		LOGGER_DEBUG("response body: " << body_);
		if (error != boost::asio::error::eof)
			throw boost::system::system_error(error);
	}
	catch (std::exception& e)
	{
		interruptThread();
		LOGGER_ERROR("Exception: " << e.what());
		return 3;
	}
	interruptThread();
	LOGGER_INFO("post request succeed");
	return 0;
}


参考:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值