Boost C++ Libraries Home Libraries People FAQ More

Home | Reference | Tutorial | Examples | Design

serialization/connection.hpp

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

Home | Reference | Tutorial | Examples | Design