2012-01-31 40 views
2

私はブーストでHTTPクライアントをプログラムしたいと思う。非同期要求が完了するのを待つ

  • 最初の手順では、要求をサーバーに送信します。
  • 2番目の手順では、既に到着した応答を読み取るか、到着するまで同期的に待機します。

これは私が農産物を持っているものに似たクラスです。

class HTTPClient { 
public: 
    void sendTheRequest(...) { 
     // Send the HTTP request 
    } 

    std::string getTheResponse(...) { 
     // return the already (asynchronously) received response, or wait for it 
     // in this function 
    } 
} 

誰かがこれを実現する方法を指摘することはできますか?私はブーストの知識が不足していることを恐れる。

明確化のために編集:メソッドsendTheRequestはある時点で呼び出されます。 getTheResponseが呼び出された直後かもしれませんが、これは何秒(ミリ秒)後にも発生する可能性があります。なぜ私は要求を非同期的に送信したいのですが、同時にそれを同時に待つ必要があります。

+0

あなたはあなたを助けるboost :: asioの例で何も見つかりませんでしたか? http://www.boost.org/doc/libs/1_48_0/doc/html/boost_asio/examples.html – stefanB

答えて

4

マビエは少し遅いですが、これはそれを行うべきだと私は思います。 std::future::getは、send_request_functionの値を返します。それがまだ返されていないかどうかを確認し、完了した後に返します。

class HTTPClient { 
public: 
    void sendTheRequest(...) { 
     // Send the HTTP request 
     f = std::async(std::launch::async, send_request_function, args ...); 

    } 

    std::string getTheResponse(...) { 
     // return the already (asynchronously) received response, or wait for it 
     // in this function 
     return f.get(); 

    } 
private: 
    std::future<std::string> f; 

} 
+0

恐ろしい!私が探していたもの! – Erik

+0

@Erikおそらく、コンストラクタにすでにタスクを生成して、getTheResponseが最初にタスクを生成することなく呼び出されないようにして、例外をスローする必要があります。 – inf

+0

C++ 11を使用せずに同じことを行う方法は? – rank1

0

boostに付属のこの例の非同期httpクライアントを使用しないのはなぜですか?

// 
// async_client.cpp 
// ~~~~~~~~~~~~~~~~ 
// 
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#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) 
    { 
    // 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. 
    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"; 

    // Start an asynchronous resolve to translate the server and service names 
    // into a list of endpoints. 
    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) 
    { 
     // Attempt a connection to each endpoint in the list until we 
     // successfully establish a connection. 
     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) 
    { 
     // The connection was successful. Send the request. 
     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) 
    { 
     // 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::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) 
    { 
     // 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\n"; 
     return; 
     } 
     if (status_code != 200) 
     { 
     std::cout << "Response returned with status code "; 
     std::cout << status_code << "\n"; 
     return; 
     } 

     // Read the response headers, which are terminated by a blank line. 
     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) 
    { 
     // Process the response headers. 
     std::istream response_stream(&response_); 
     std::string header; 
     while (std::getline(response_stream, header) && header != "\r") 
     std::cout << header << "\n"; 
     std::cout << "\n"; 

     // Write whatever content we already have to output. 
     if (response_.size() > 0) 
     std::cout << &response_; 

     // Start reading remaining data until EOF. 
     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) 
    { 
     // Write all of the data that has been read so far. 
     std::cout << &response_; 

     // Continue reading remaining data until EOF. 
     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 main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 3) 
    { 
     std::cout << "Usage: async_client <server> <path>\n"; 
     std::cout << "Example:\n"; 
     std::cout << " async_client www.boost.org /LICENSE_1_0.txt\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 
    client c(io_service, argv[1], argv[2]); 
    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cout << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
+0

ありがとう、私もこれを見つけました。しかし、要求が完了するのをどのように待つのですか? – Erik

+0

同期処理または非同期処理をしたいですか?私は少し混乱しています。リクエストを送信し、同じスレッドで回答を待つか? – Damian

+0

混乱して申し訳ありません。私のサンプルコードを見ると、おそらくもっと明確になります。 'sendTheRequest'メソッドはある時点で呼び出されます。おそらく 'getTheResponse'が呼び出された直後かもしれませんが、これは何秒(ミリ秒)後にも発生する可能性があります。なぜ私は要求を非同期的に送信したいのですが、同時にそれを同時に待つ必要があります。 – Erik

関連する問題