asio 0.3.8rc3 | Home | Reference | Tutorial | Examples | Design

Examples |

# serialization/connection.hpp

Go to the documentation of this file.

    00001 //
    00002 // connection.hpp
    00003 // ~~~~~~~~~~~~~~
    00004 //
    00005 // Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
    00006 //
    00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
    00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    00009 //
    00010
    00011 #ifndef SERIALIZATION_CONNECTION_HPP
    00012 #define SERIALIZATION_CONNECTION_HPP
    00013
    00014 #include <asio.hpp>
    00015 #include <boost/archive/text_iarchive.hpp>
    00016 #include <boost/archive/text_oarchive.hpp>
    00017 #include <boost/bind.hpp>
    00018 #include <boost/shared_ptr.hpp>
    00019 #include <boost/tuple/tuple.hpp>
    00020 #include <iomanip>
    00021 #include <string>
    00022 #include <sstream>
    00023 #include <vector>
    00024
    00025 namespace s11n_example {
    00026
    00028
    00034 class connection
    00035 {
    00036 public:
    00038   connection(asio::io_service& io_service)
    00039     : socket_(io_service)
    00040   {
    00041   }
    00042
    00045   asio::ip::tcp::socket& socket()
    00046   {
    00047     return socket_;
    00048   }
    00049
    00051   template <typename T, typename Handler>
    00052   void async_write(const T& t, Handler handler)
    00053   {
    00054     // Serialize the data first so we know how large it is.
    00055     std::ostringstream archive_stream;
    00056     boost::archive::text_oarchive archive(archive_stream);
    00057     archive << t;
    00058     outbound_data_ = archive_stream.str();
    00059
    00060     // Format the header.
    00061     std::ostringstream header_stream;
    00062     header_stream << std::setw(header_length)
    00063       << std::hex << outbound_data_.size();
    00064     if (!header_stream || header_stream.str().size() != header_length)
    00065     {
    00066       // Something went wrong, inform the caller.
    00067       asio::error_code error(asio::error::invalid_argument);
    00068       socket_.io_service().post(boost::bind(handler, error));
    00069       return;
    00070     }
    00071     outbound_header_ = header_stream.str();
    00072
    00073     // Write the serialized data to the socket. We use "gather-write" to send
    00074     // both the header and the data in a single write operation.
    00075     std::vector<asio::const_buffer> buffers;
    00076     buffers.push_back(asio::buffer(outbound_header_));
    00077     buffers.push_back(asio::buffer(outbound_data_));
    00078     asio::async_write(socket_, buffers, handler);
    00079   }
    00080
    00082   template <typename T, typename Handler>
    00083   void async_read(T& t, Handler handler)
    00084   {
    00085     // Issue a read operation to read exactly the number of bytes in a header.
    00086     void (connection::*f)(
    00087         const asio::error_code&,
    00088         T&, boost::tuple<Handler>)
    00089       = &connection::handle_read_header<T, Handler>;
    00090     asio::async_read(socket_, asio::buffer(inbound_header_),
    00091         boost::bind(f,
    00092           this, asio::placeholders::error, boost::ref(t),
    00093           boost::make_tuple(handler)));
    00094   }
    00095
    00099   template <typename T, typename Handler>
    00100   void handle_read_header(const asio::error_code& e,
    00101       T& t, boost::tuple<Handler> handler)
    00102   {
    00103     if (e)
    00104     {
    00105       boost::get<0>(handler)(e);
    00106     }
    00107     else
    00108     {
    00109       // Determine the length of the serialized data.
    00110       std::istringstream is(std::string(inbound_header_, header_length));
    00111       std::size_t inbound_data_size = 0;
    00112       if (!(is >> std::hex >> inbound_data_size))
    00113       {
    00114         // Header doesn't seem to be valid. Inform the caller.
    00115         asio::error_code error(asio::error::invalid_argument);
    00116         boost::get<0>(handler)(error);
    00117         return;
    00118       }
    00119
    00120       // Start an asynchronous call to receive the data.
    00121       inbound_data_.resize(inbound_data_size);
    00122       void (connection::*f)(
    00123           const asio::error_code&,
    00124           T&, boost::tuple<Handler>)
    00125         = &connection::handle_read_data<T, Handler>;
    00126       asio::async_read(socket_, asio::buffer(inbound_data_),
    00127         boost::bind(f, this,
    00128           asio::placeholders::error, boost::ref(t), handler));
    00129     }
    00130   }
    00131
    00133   template <typename T, typename Handler>
    00134   void handle_read_data(const asio::error_code& e,
    00135       T& t, boost::tuple<Handler> handler)
    00136   {
    00137     if (e)
    00138     {
    00139       boost::get<0>(handler)(e);
    00140     }
    00141     else
    00142     {
    00143       // Extract the data structure from the data just received.
    00144       try
    00145       {
    00146         std::string archive_data(&inbound_data_[0], inbound_data_.size());
    00147         std::istringstream archive_stream(archive_data);
    00148         boost::archive::text_iarchive archive(archive_stream);
    00149         archive >> t;
    00150       }
    00151       catch (std::exception& e)
    00152       {
    00153         // Unable to decode data.
    00154         asio::error_code error(asio::error::invalid_argument);
    00155         boost::get<0>(handler)(error);
    00156         return;
    00157       }
    00158
    00159       // Inform caller that data has been received ok.
    00160       boost::get<0>(handler)(e);
    00161     }
    00162   }
    00163
    00164 private:
    00166   asio::ip::tcp::socket socket_;
    00167
    00169   enum { header_length = 8 };
    00170
    00172   std::string outbound_header_;
    00173
    00175   std::string outbound_data_;
    00176
    00178   char inbound_header_[header_length];
    00179
    00181   std::vector<char> inbound_data_;
    00182 };
    00183
    00184 typedef boost::shared_ptr<connection> connection_ptr;
    00185
    00186 } // namespace s11n_example
    00187
    00188 #endif // SERIALIZATION_CONNECTION_HPP

asio 0.3.8rc3 | Home | Reference | Tutorial | Examples | Design