1.23.2011

mogmail – connector module with boost::asio

mogmail - boost::asio を利用したコネクタ

・connector.h

   1: // Copyright (c) 2011 Mog Project. All rights reserved.
   2:  
   3: #ifndef _MOG_NET_CONNECTER_H_
   4: #define _MOG_NET_CONNECTER_H_
   5: #pragma once
   6:  
   7: #include <string>
   8: #include <deque>
   9: #include <boost/scoped_ptr.hpp>
  10: #ifdef _WIN32
  11: #define _WIN32_WINNT 0x0501
  12: #endif  // _WIN32
  13: #include <boost/asio.hpp>
  14:  
  15: namespace mog {
  16: namespace net {
  17:  
  18: // A class manages text-based TCP connection.
  19: class Connecter {
  20:  public:
  21:   // Create connection to server.
  22:   Connecter(std::string const& address, std::string const& port, bool spool = false);
  23:   // Disconnect from server.
  24:   ~Connecter();
  25:   // Write one line.
  26:   void WriteLine(std::string const& line);
  27:   // Read one line.
  28:   void ReadLine(std::string * line);
  29:   // Flush buffered messages.
  30:   void Flush();
  31:   // If there is no response, return true.
  32:   bool IsEmpty() const;
  33:   // Mutator of spool switch.
  34:   void set_spool(bool spool) { spool_ = spool; }
  35:   // Accessor of spool switch.
  36:   bool spool() const { return spool_; }
  37:  
  38:  private:
  39:   static size_t const                             SOCKET_SIZE = 8192;
  40:   boost::asio::io_service                         io_service_;
  41:   boost::scoped_ptr<boost::asio::ip::tcp::socket> socket_;
  42:   std::deque<std::string>                         buffer_;
  43:   bool spool_;
  44:  
  45:   // Send requests.
  46:   void Request(std::string const& request);
  47:   // Recieve response.
  48:   void Response();
  49: };
  50:  
  51: }  // namespace net
  52: }  // namespace mog
  53: #endif  // _MOG_NET_CONNECTER_H_
・connector.cc
   1: // Copyright (c) 2011 Mog Project. All rights reserved.
   2:  
   3: #include "connecter.h"
   4: #include <iostream>
   5: #include <algorithm>
   6:  
   7: namespace mog {
   8: namespace net {
   9:  
  10: ////////////////////////////////////////////////////////////////////////////////
  11: // Connecter
  12: Connecter::Connecter(std::string const& address, std::string const& port, bool spool)
  13:     : spool_(spool), socket_(new boost::asio::ip::tcp::socket(io_service_)) {
  14:   boost::asio::ip::tcp::resolver resolver(io_service_);
  15:   boost::asio::ip::tcp::resolver::query query(address, port);
  16:   boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
  17:   boost::asio::ip::tcp::resolver::iterator end;
  18:  
  19:   boost::system::error_code error = boost::asio::error::host_not_found;
  20:  
  21:   while (error && endpoint_iterator != end) {
  22:     socket_->close();
  23:     socket_->connect(*endpoint_iterator++, error);
  24:   }
  25:   if (error) {
  26:     throw boost::system::system_error(error);
  27:   }
  28: }
  29:  
  30: Connecter::~Connecter() {
  31:   try {
  32:     socket_->close();
  33:   } catch(...) {}
  34: }
  35:  
  36: void Connecter::WriteLine(std::string const& line) {
  37:   Request(line + '\n');
  38: }
  39:  
  40: void Connecter::ReadLine(std::string * line) {
  41:   if ( buffer_.empty() ) { Response(); }
  42:   *line = buffer_.front();
  43:   buffer_.pop_front();
  44: }
  45:  
  46: void Connecter::Request(std::string const& request) {
  47:   socket_->write_some(boost::asio::buffer(request, request.size()));
  48:   if (spool_) { std::cerr << "[SEND] " << request; }
  49: }
  50:  
  51: void Connecter::Response() {
  52:   boost::array<char, SOCKET_SIZE> buf;
  53:   std::stringstream str;
  54:  
  55:   // Recieve socket.
  56:   for (;;) {
  57:     size_t length = socket_->read_some(boost::asio::buffer(buf));
  58:     str.write(buf.data(), length);
  59:     if (SOCKET_SIZE != length) { break; }
  60:   }
  61:  
  62:   // Convert lines to buffer.
  63:   std::string line;
  64:   while (std::getline(str, line, '\n')) {
  65:     line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());  // Remove carriage return.
  66:     buffer_.push_back(line);
  67:     if (spool_) { std::cerr << "[RECV] " << line << '\n'; }
  68:   }
  69: }
  70:  
  71: void Connecter::Flush() {
  72:   if (socket_->available()) {  // Thrown on faulure, boost::system::system_error.
  73:     Response();
  74:   }
  75:   buffer_.clear();
  76: }
  77:  
  78: bool Connecter::IsEmpty() const {
  79:   if (buffer_.empty() && !socket_->available()) { return true; }
  80:   return false;
  81: }
  82:  
  83: }  // namespace net
  84: }  // namespace mog
参考:Erase-Removeイディオム
http://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/%E6%B6%88%E5%8E%BB%E3%83%BB%E5%89%8A%E9%99%A4(Erase-Remove)

0 件のコメント:

コメントを投稿