堕(惰)プログラマ開発記録 このページをアンテナに追加 RSSフィード Twitter

2011-02-19

Boost.Asioによる非同期通信2

昨日の続き。全体を非同期通信にしてみた。

クラスで色々まとめてね。


一応動くんだよね。

以下がコード。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <stdexcept>

class tcp_client{
public:
  tcp_client(boost::asio::io_service& io_service)
    : io_service_(io_service), socket_(io_service_), resolver_(io_service_) { }

  void write(const std::string& host,boost::asio::streambuf *request){
    request_ = request;
    boost::asio::ip::tcp::resolver::query query(host, "http");
    resolver_.async_resolve(
      query,
      boost::bind(&tcp_client::handle_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)
      );
  }
  
  void read(std::string& response){response = response_;}

  boost::asio::io_service& io_service(){return this->io_service_;}
  
private:
  //async_resolve後ハンドル
  void handle_resolve(const boost::system::error_code& err,boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
  {
    if(!err)
    {
      //正常
      boost::asio::ip::tcp::endpoint endpoint= *endpoint_iterator;
      socket_.async_connect(
        endpoint,
        boost::bind(&tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)
        );

    }
    else throw std::invalid_argument("Error: "+err.message());
  }

  //async_connect後ハンドル
  void handle_connect(const boost::system::error_code& err,boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
  {
    if(!err)
    {
      //正常接続
      boost::asio::async_write(
      socket_,
      *request_,
      boost::bind(&tcp_client::handle_write_request, this, boost::asio::placeholders::error)
      );
    }
    else if(endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())
    {
      //接続ミス
      socket_.close();
      boost::asio::ip::tcp::endpoint endpoint= *endpoint_iterator;
      socket_.async_connect(
        endpoint,
        boost::bind(&tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)
        );

    }
    else throw std::invalid_argument("Error: "+err.message());
  }

  //async_write後ハンドル
  void handle_write_request(const boost::system::error_code& err)
  {
    if(!err)
    {
      //正常送信
      boost::asio::async_read_until(
      socket_,
      response_stream_,
      "\r\n",
      boost::bind(&tcp_client::handle_read_status, this, boost::asio::placeholders::error)
      );
    }
    else throw std::invalid_argument("Error: "+err.message());
  }

  //async_read_until後ハンドル
  void handle_read_status(const boost::system::error_code& err)
  {
    if(!err)
    {
      //正常送信
      std::istream response_stream(&response_stream_);
      //レスポンスチェック
      std::string http_version;
      response_stream >> http_version;
      unsigned int status_code;
      response_stream >> status_code;
      std::string status_message;
      response_stream >> status_message;
      
      if (!response_stream || http_version.substr(0, 5) != "HTTP/")
      {
        throw std::invalid_argument("Invalid response");
      }

      boost::asio::async_read_until(
        socket_,
        response_stream_,
        "\r\n\r\n",
        boost::bind(&tcp_client::handle_read_header, this, boost::asio::placeholders::error)
        );
    }
    else throw std::invalid_argument("Error: "+err.message());
  }

  //handle_read_status後ハンドル
  void handle_read_header(const boost::system::error_code& err)
  {
    if(!err)
    {
      //正常送信
      std::istream response_stream(&response_stream_);
      std::string header;
      while (std::getline(response_stream, header) && header != "\r")
        std::cout << header << "\n";
      std::cout << "\n";
      
      if (response_stream_.size() > 0)
      response_ = static_cast<std::string>(boost::asio::buffer_cast<const char*>(response_stream_.data()));
      
      boost::asio::async_read(
        socket_,
        response_stream_,
        boost::asio::transfer_at_least(1),
        boost::bind(&tcp_client::handle_read_content, this, boost::asio::placeholders::error)
        );      
    }
    else throw std::invalid_argument("Error: "+err.message());
  }

  //handle_read_header後ハンドル
  void handle_read_content(const boost::system::error_code& err)
  {
    if(!err)
    {
    response_ = static_cast<std::string>(boost::asio::buffer_cast<const char*>(response_stream_.data()));
      
      boost::asio::async_read(
        socket_,
        response_stream_,
        boost::asio::transfer_at_least(1),
        boost::bind(&tcp_client::handle_read_content,
        this,
        boost::asio::placeholders::error)
        );
    }
    else if (err != boost::asio::error::eof)
    {
      std::cout << "Error: " << err << "\n";
    }
  }

  boost::asio::io_service& io_service_;
  boost::asio::streambuf *request_;
  boost::asio::streambuf response_stream_;
  std::string response_;
  boost::asio::ip::tcp::socket socket_;
  boost::asio::ip::tcp::resolver resolver_;
};

int main(){
  try
  {
    boost::asio::io_service io_service;
  
    boost::asio::streambuf buffer;
    std::ostream ss(&buffer);
    boost::asio::streambuf response;

    ss << "GET / HTTP/1.1\r\n";
    ss << "Host: godai.e-whs.net\r\n";
    ss << "Accept: */*\r\n";
    ss << "Connection: close\r\n\r\n";
    ss << std::flush;

    tcp_client tcp(io_service);
    tcp.write("godai.e-whs.net",&buffer);
    io_service.run();

    std::string A;
    tcp.read(A);

  }
  catch (std::exception& e)
  {
    std::cout << "Exception: " << e.what() << "\n";
  }

  return 0;
}

次はSSLの非同期を実装しようと思ってる。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/godai_0519/20110219/1299900558