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
