2014-03-18 112 views
1

在boost asio異步http客戶端中,如何設置http下載操作的超時時間?Boost asio異步HTTP客戶端超時?

我檢查了這些例子,但他們沒有提供超時的http客戶端。

更具體地說,如何修改這個例子來支持超時:

#include <iostream> 
#include <istream> 
#include <ostream> 
#include <string> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 

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

class client 
{ 
public: 
    client(boost::asio::io_service& io_service, 
     const std::string& server, const std::string& path) 
    : resolver_(io_service), 
     socket_(io_service) 
    { 
    std::ostream request_stream(&request_); 
    request_stream << "GET " << path << " HTTP/1.0\r\n"; 
    request_stream << "Host: " << server << "\r\n"; 
    request_stream << "Accept: */*\r\n"; 
    request_stream << "Connection: close\r\n\r\n"; 

    tcp::resolver::query query(server, "http"); 
    resolver_.async_resolve(query, 
     boost::bind(&client::handle_resolve, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::iterator)); 
    } 

private: 
    void handle_resolve(const boost::system::error_code& err, 
     tcp::resolver::iterator endpoint_iterator) 
    { 
    if (!err) 
    { 
     boost::asio::async_connect(socket_, endpoint_iterator, 
      boost::bind(&client::handle_connect, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error: " << err.message() << "\n"; 
    } 
    } 

    void handle_connect(const boost::system::error_code& err) 
    { 
    if (!err) 
    { 
     boost::asio::async_write(socket_, request_, 
      boost::bind(&client::handle_write_request, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error: " << err.message() << "\n"; 
    } 
    } 

    void handle_write_request(const boost::system::error_code& err) 
    { 
    if (!err) 
    { 
     boost::asio::async_read_until(socket_, response_, "\r\n", 
      boost::bind(&client::handle_read_status_line, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error: " << err.message() << "\n"; 
    } 
    } 

    void handle_read_status_line(const boost::system::error_code& err) 
    { 
    if (!err) 
    { 
     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\n"; 
     return; 
     } 
     if (status_code != 200) 
     { 
     std::cout << "Response returned with status code "; 
     std::cout << status_code << "\n"; 
     return; 
     } 

     boost::asio::async_read_until(socket_, response_, "\r\n\r\n", 
      boost::bind(&client::handle_read_headers, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error: " << err << "\n"; 
    } 
    } 

    void handle_read_headers(const boost::system::error_code& err) 
    { 
    if (!err) 
    { 
     std::istream response_stream(&response_); 
     std::string header; 
     while (std::getline(response_stream, header) && header != "\r") 
     std::cout << header << "\n"; 
     std::cout << "\n"; 

     if (response_.size() > 0) 
     std::cout << &response_; 

     boost::asio::async_read(socket_, response_, 
      boost::asio::transfer_at_least(1), 
      boost::bind(&client::handle_read_content, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error: " << err << "\n"; 
    } 
    } 

    void handle_read_content(const boost::system::error_code& err) 
    { 
    if (!err) 
    { 
     std::cout << &response_; 

     boost::asio::async_read(socket_, response_, 
      boost::asio::transfer_at_least(1), 
      boost::bind(&client::handle_read_content, this, 
      boost::asio::placeholders::error)); 
    } 
    else if (err != boost::asio::error::eof) 
    { 
     std::cout << "Error: " << err << "\n"; 
    } 
    } 

    tcp::resolver resolver_; 
    tcp::socket socket_; 
    boost::asio::streambuf request_; 
    boost::asio::streambuf response_; 
}; 

int http_download(string &server, string &path) 
{ 
    try 
    { 
    boost::asio::io_service io_service; 
    client c(io_service, server, path); 
    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cout << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
+0

可能相關:http://stackoverflow.com/questions/291871/how-to-set-a-timeout-on-blocking-sockets-in-boost-asio –

+0

這傢伙有並沒有對協議http做任何說明。此外,在那裏找不到有用的便攜式信息。我正在尋找一種便攜式的方式來做到這一點。 – Luka

回答

2

如果需要簡單到10秒鐘http_download出口(爲例) 你可以用這種方式:

添加deadline_timer類客戶:

boost::asio::deadline_timer timer_; 

Initialiaze它在構造函數中:

timer_(io_service,boost::posix_time::seconds(10)), 

定時器添加處理程序:

timer_.async_wait(boost::bind(&client::close_connection, this)); 

在類客戶端創建方法close_connection,其中您需要關閉套接字 。 可能的構造:

client(boost::asio::io_service& io_service, 
     const std::string& server, const std::string& path) 
    : resolver_(io_service), 
     socket_(io_service), 
     timer_(io_service,boost::posix_time::seconds(10)) 
    { 
    timer_.async_wait(boost::bind(&client::close_connection, this)); 
    std::ostream request_stream(&request_); 
    request_stream << "GET " << path << " HTTP/1.0\r\n"; 
    request_stream << "Host: " << server << "\r\n"; 
    request_stream << "Accept: */*\r\n"; 
    request_stream << "Connection: close\r\n\r\n"; 
    ... 

    }