Revision: 43274
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at March 20, 2011 13:56 by liouys
Initial Code
// // async_client.cpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 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/function.hpp> #include <boost/thread/once.hpp> #include <boost/thread.hpp> #include <boost/asio.hpp> #include <boost/bind.hpp> using boost::asio::ip::tcp; class client { public: typedef boost::function<void(client&)> on_complete_callback; public: client(boost::asio::io_service& io_service) : resolver_(io_service) , socket_(io_service) , io_service_(io_service) { } ~client() { io_thread_.join(); } void navigate(const std::string& server, const std::string& path) { if (socket_.is_open()) { boost::system::error_code ignored_ec; socket_.close(ignored_ec); } std::ostream request_stream(&request_); request_stream << "GET " << path << " HTTP/1.0 "; request_stream << "Host: " << server << " "; request_stream << "Accept: */* "; request_stream << "Connection: close "; tcp::resolver::query query(server, "http"); resolver_.async_resolve(query, boost::bind(&client::handle_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); io_thread_.swap(boost::thread(boost::bind(&client::io_service_run, this))); } void regiseter_complete_callback(on_complete_callback callback) { on_complete_callback_ = callback; } void close_socket() { boost::system::error_code ignored_ec; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); socket_.close(ignored_ec); } void io_service_run() { boost::mutex::scoped_try_lock try_lock(io_mutex_); if (!try_lock) { return ; } io_service_.run(); io_service_.reset(); } private: void handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator) { if (!err) { // Attempt a connection to the first endpoint in the list. Each endpoint // will be tried until we successfully establish a connection. tcp::endpoint endpoint = *endpoint_iterator; socket_.async_connect(endpoint, boost::bind(&client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } else { std::cout << "Error: " << err.message() << "\n"; } } void handle_connect(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator) { 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 if (endpoint_iterator != tcp::resolver::iterator()) { // The connection failed. Try the next endpoint in the list. socket_.close(); tcp::endpoint endpoint = *endpoint_iterator; socket_.async_connect(endpoint, boost::bind(&client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } 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_, " ", 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_, " ", 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"; } else { on_complete_callback_(*this); } } tcp::resolver resolver_; tcp::socket socket_; boost::asio::streambuf request_; boost::asio::streambuf response_; boost::asio::io_service& io_service_; boost::thread io_thread_; boost::mutex io_mutex_; on_complete_callback on_complete_callback_; }; void complete(client& cli) { } 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 cli(io_service); cli.regiseter_complete_callback(boost::bind(&complete, boost::ref<client>(cli))); cli.navigate(argv[1], argv[2]); std::string in; std::cout << "type 'exit' to exit.\nprompt # "; for (;;) { char c = getchar(); if (c == '\n' || c == EOF ) { if (in == "exit") { io_service.post(boost::bind(&client::close_socket, &cli)); break; } else if (in == "r") { cli.navigate(argv[1], argv[2]); } else if(in != "") { system(in.c_str()); // std::cout << "Bad command ! \n"; } std::cout << "prompt # "; in = ""; } else { in += c; } } } catch (std::exception& e) { std::cout << "Exception: " << e.what() << "\n"; } return 0; }
Initial URL
Initial Description
Initial Title
boost.asio异æ¥é‡è¿ž
Initial Tags
Net
Initial Language
C++