boost::asio 異步主動連接多個服務器

  1. #include <boost/asio/deadline_timer.hpp>
  2. #include <boost/asio/io_service.hpp>
  3. #include <boost/asio/ip/tcp.hpp>
  4. #include <boost/asio/read_until.hpp>
  5. #include <boost/asio/streambuf.hpp>
  6. #include <boost/asio/write.hpp>
  7. #include <boost/asio.hpp>
  8. #include <boost/bind.hpp>
  9. #include <boost/shared_ptr.hpp>
  10. #include <boost/enable_shared_from_this.hpp>
  11. #include <iostream>
  12. #include <set>
  13. #include <map>
  14. #include "Message.hpp"
  15. #include "SQLite.hpp"

  16. using boost::asio::deadline_timer;
  17. using boost::asio::ip::tcp;
  18. using boost::asio::ip::udp;

  19. using namespace std;
  20. using namespace PWRD;
  21. using namespace PWRD::SQL;
  22. using namespace PWRD::Protocol;

  23. typedef map<string, int> Peers;
  24. typedef map<string, int> Stats;
  25. typedef map<string, string> Files;
  26. typedef map<string, tcp::socket* > Sockets;
  27. #define DEADLINE 10
  28. #define MAXLEN 1024
  29. #define SECONDS 5

  30. namespace PWRD{
  31.     namespace Network{
  32.         class Session{
  33.             public: 
  34.                 Session(boost::asio::ip::tcp::socket &_socket, boost::asio::io_service &io_service, const char *path);
  35.                 ~Session();
  36.                 void start();

  37.                 void stop();
  38.                 void delivery(string &ip);

  39.             private:
  40.                 void handle_connect(const boost::system::error_code& ec,
  41.                         tcp::resolver::iterator endpoint_iter);

  42.                 void start_read();

  43.                 void handle_read_header(const boost::system::error_code& ec);

  44.                 void start_delivery();

  45.                 void handle_read_body(const boost::system::error_code& ec);

  46.                 void start_write_heartbeat();

  47.                 void handle_write_heartbeat(const boost::system::error_code& ec);
  48.                 void handle_wait(const boost::system::error_code& ec);
  49.                 void handle_write_config(const boost::system::error_code& ec, Configure &conf);

  50.             private:
  51.                 bool stopped_;
  52.                 tcp::socket &socket_;
  53.                 Header header_;
  54.                 HeartbeatMessage heartbeat_message_;
  55.                 DataMessage packet_message_;
  56.                 ConfigMessage conf_message_;
  57.                 deadline_timer heartbeat_timer_;
  58.                 Callback *callback_;
  59.                 char *input_stream_;

  60.         };

  61.         class SessionPool{
  62.             public:
  63.                 SessionPool();
  64.                 ~SessionPool();
  65.                 void join(string&, Session *);
  66.                 void delivery(string&);
  67.                 void leave(string &ip);

  68.             private:
  69.                 std::map<string, Session *> session_pool_;    
  70.         };
  71.         /************************************************************
  72.          * Usage: Client will connect to every server and it's never
  73.          *     stopped until you shutdown it. Connect action will 
  74.          *    start in every DEADLINE seconds
  75.          ************************************************************/
  76.         class Client{
  77.             public:
  78.                 void stop();
  79.                 void start();
  80.                 Client(boost::asio::io_service &_io_service, boost::asio::io_service &_io_service_data, const char *_sqlite);
  81.             protected:
  82.                 void handle_wait_update();
  83.                 void handle_update();
  84.                 void start_connect();
  85.                 void handle_connect(const boost::system::error_code& ec,Peers::iterator it);
  86.                 void handle_deadline();
  87.                 void check_all();
  88.             private:

  89.                 Peers peers_;
  90.                 Sockets sockets_;
  91.                 Stats status_;
  92.                 Files files_;

  93.                 deadline_timer deadline_;
  94.                 boost::asio::io_service &io_service_;
  95.                 const char * sqlite_;
  96.                 bool all_;

  97.                 SessionPool session_pool_;

  98.                 boost::asio::io_service &io_service_data_;

  99.         };
  100.     };
  101. };

 

ATC.cpp

  1. #include "ATC.hpp"
  2. namespace PWRD{
  3.     namespace Network{
  4.         //-------------------------------------------------------------------------

  5.         //Session

  6.         //-------------------------------------------------------------------------

  7.         Session::Session(boost::asio::ip::tcp::socket &_socket, boost::asio::io_service &io_service, const char *path)
  8.             :socket_(_socket),
  9.             heartbeat_timer_(io_service),
  10.             stopped_(false)
  11.         {
  12.             callback_ = new Callback(path);
  13.             input_stream_ = new char[MAXLEN];
  14.         }

  15.         Session::~Session(){
  16.             delete callback_;
  17.             delete input_stream_;    
  18.         }
  19.         void Session::start(){
  20.             start_read();
  21.             start_write_heartbeat();
  22.         }

  23.         void Session::stop(){
  24.             stopped_ = true;
  25.             socket_.close();
  26.             heartbeat_timer_.cancel();
  27.         }

  28.         void Session::start_read(){
  29.             socket_.async_receive( 
  30.                     boost::asio::buffer(&header_, HEADERLEN),
  31.                     boost::bind(&Session::handle_read_header, this, 
  32.                         boost::asio::placeholders::error)
  33.                     );
  34.         }

  35.         void Session::handle_read_header(const boost::system::error_code& ec){
  36.             if(stopped_)
  37.                 return;    
  38.             if(!ec){
  39.                 if(HEARTBEAT == header_.type){
  40.                     logs.write_log(NORMAL, "info:Receive heartbeat message");    
  41.                     //heartbeat_timer_.expires_from_now(boost::posix_time::seconds(SECONDS));

  42.                     start_read();
  43.                 }    
  44.                 else if(PACKET == header_.type){
  45.                     socket_.async_receive(
  46.                             boost::asio::buffer(input_stream_, header_.length),
  47.                             boost::bind(&Session::handle_read_body, this, 
  48.                                 boost::asio::placeholders::error)
  49.                             );
  50.                     logs.write_log(NORMAL, "info:Receive Packet message: %d bytes", header_.length);    
  51.                 }
  52.             }
  53.             else{
  54.                 logs.write_log(NORMAL, "Error on receive: %s", (ec.message()).c_str());    
  55.                 stop();
  56.             }
  57.         }

  58.         void Session::handle_read_body(const boost::system::error_code& ec){
  59.             if(stopped_)
  60.                 return;    
  61.             if(!ec){
  62.                 if(packet_message_.Parse(input_stream_, header_.length)){
  63.                     Packet * packet = packet_message_.pack();
  64.                     logs.write_log(NORMAL, "info:Receive data: %s", (packet->data()).c_str());
  65.                     callback_->Write(packet);            
  66.                 }

  67.                 start_read();
  68.             }
  69.             else{
  70.                 logs.write_log(NORMAL, "Error on receive: %s", (ec.message()).c_str());    
  71.                 stop();
  72.             }
  73.         }
  74.         void Session::start_write_heartbeat(){
  75.             if(stopped_)
  76.                 return ;    
  77.             Header header;
  78.             header.length = 0;
  79.             header.type = HEARTBEAT;
  80.             boost::asio::async_write(socket_, boost::asio::buffer(&header, HEADERLEN),
  81.                     boost::bind(&Session::handle_write_heartbeat, this,
  82.                         boost::asio::placeholders::error    ));
  83.             logs.write_log(NORMAL, "info:Send heartbeat message--->");
  84.         }
  85.         void Session::handle_write_heartbeat(const boost::system::error_code& ec){
  86.             if(stopped_)
  87.                 return ;    

  88.             if(!ec){
  89.                 heartbeat_timer_.expires_from_now(boost::posix_time::seconds(SECONDS));
  90.                 heartbeat_timer_.async_wait(boost::bind(&Session::start_write_heartbeat, this));

  91.             }
  92.             else{
  93.                 logs.write_log(NORMAL, "info:Error on heartbeat: %s ", (ec.message()).c_str());
  94.                 stop();

  95.             }
  96.         }
  97.         void Session::start_delivery(){
  98.             if(stopped_)
  99.                 return ;    
  100.             /* *
  101.              * SQLite append
  102.              * */
  103.             Configure conf;
  104.             conf_message_.set_conf(conf);
  105.             conf_message_.Serialize();
  106.             header_.length = conf_message_.length();
  107.             header_.type = CONFIG;
  108.             socket_.async_send(
  109.                     boost::asio::buffer(&header_,    HEADERLEN),
  110.                     boost::bind(&Session::handle_write_config, this, _1, conf)
  111.                     //boost::asio::placeholders::error, conf)

  112.                 );
  113.         }

  114.         void Session::delivery(string &ip){
  115.             if(stopped_)
  116.                 return ;    
  117.             /* *
  118.              * SQLite append
  119.              * */
  120.             Configure conf;
  121.             conf_message_.set_conf(conf);
  122.             conf_message_.Serialize();
  123.             header_.length = conf_message_.length();
  124.             header_.type = CONFIG;
  125.             socket_.async_send(
  126.                     boost::asio::buffer(&header_,    HEADERLEN),
  127.                     boost::bind(&Session::handle_write_config, this, _1, conf)
  128.                     //boost::asio::placeholders::error, conf)

  129.                 );
  130.         }

  131.         void Session::handle_write_config(const boost::system::error_code& ec, Configure &conf){
  132.             if(stopped_)
  133.                 return ;    

  134.             if(!ec){
  135.                 socket_.async_send(
  136.                         boost::asio::buffer(conf_message_.data(), 
  137.                             conf_message_.length()), 
  138.                         boost::bind(&Session::handle_wait, this, _1)

  139.                         );
  140.             }
  141.         }

  142.         void Session::handle_wait(const boost::system::error_code &ec){
  143.             return;    
  144.         }
  145.         
  146.         //-------------------------------------------------------------------------

  147.         //SessionPool

  148.         //-------------------------------------------------------------------------

  149.         SessionPool::SessionPool(){
  150.         }

  151.         SessionPool::~SessionPool(){
  152.         
  153.         }

  154.         void SessionPool::join(string &ip, Session *sess){
  155.             session_pool_[ip] = sess;    
  156.         }

  157.         void SessionPool::delivery(string &ip){
  158.             session_pool_[ip]->delivery(ip);    
  159.         }

  160.         void SessionPool::leave(string &ip){
  161.             if(NULL == session_pool_[ip]){
  162.                 delete session_pool_[ip];    
  163.             }
  164.             session_pool_[ip] = NULL;    
  165.         }

  166.         //-------------------------------------------------------------------------

  167.         //Client

  168.         //-------------------------------------------------------------------------

  169.         Client::Client(boost::asio::io_service &_io_service, boost::asio::io_service &_io_service_data, const char *_sqlite)
  170.             :io_service_(_io_service),
  171.             io_service_data_(_io_service_data),
  172.             deadline_(_io_service),
  173.             sqlite_(_sqlite), all_(false){

  174.             }
  175.         void Client::start()
  176.         {
  177.             //IP Table

  178.             if(NULL == sqlite_){
  179.                 logs.write_log(NORMAL, "Sqlite dbname is invalid");
  180.                 return;
  181.             }    
  182.             SQLite::get_instance(sqlite_);
  183.             AddrMap &map_ = SQLite::lookup();
  184.             logs.write_log(NORMAL, "Get %d records", map_.size());
  185.             AddrMap::iterator iter = map_.begin();
  186.             for(; iter != map_.end(); iter++){
  187.                 Vector vect = iter->second;        
  188.                 string ip = vect[1], port = vect[2];
  189.                 status_[ip] = -1;
  190.                 peers_[ip] = std::atoi(port.c_str());
  191.                 sockets_[ip] = new boost::asio::ip::tcp::socket(io_service_);
  192.                 files_[ip] = "/tmp/file";
  193.                 //times_[ip] = boost::asio::deadline_timer(io_service_);

  194.             }

  195.             //start to connect

  196.             start_connect();
  197.             deadline_.async_wait(boost::bind(&Client::handle_deadline, this));

  198.         }
  199.         void Client::stop(){
  200.             deadline_.cancel();
  201.         }

  202.         void Client::handle_wait_update(){

  203.         }
  204.         void Client::handle_update(){

  205.         }
  206.         void Client::start_connect(){
  207.             if(peers_.size() > 0){
  208.                 deadline_.expires_from_now(boost::posix_time::seconds(DEADLINE));
  209.                 for(Peers::iterator it = peers_.begin();
  210.                         it != peers_.end(); it++){

  211.                     if( status_[it->first] < 0){
  212.                         logs.write_log(NORMAL, "Start to connect: %s:%d", (it->first).c_str(), it->second);    

  213.                         sockets_[it->first]->async_connect(
  214.                                 boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(it->first), it->second), 
  215.                                 boost::bind(&Client::handle_connect, 
  216.                                     this, _1, it));

  217.                     }
  218.                 }
  219.             }
  220.             else{
  221.                 stop();
  222.             }

  223.         }


  224.         void Client::handle_connect(const boost::system::error_code& ec,
  225.                 Peers::iterator it){
  226.             if(!sockets_[it->first]->is_open()){
  227.                 logs.write_log(NORMAL, "Connect time out");    
  228.                 return;
  229.             }
  230.             else if(ec){
  231.                 logs.write_log(NORMAL, "Connect error:%s", (ec.message()).c_str());
  232.                 //sockets_[it->first]->close();

  233.                 return;
  234.             }
  235.             else{
  236.                 logs.write_log(NORMAL, "Connect ok! it was conected with %s:%d", (it->first).c_str(), it->second);    
  237.                 status_[it->first] = 1;
  238.                 Session * ss = new Session(*(sockets_[it->first]), io_service_data_, (files_[it->first]).c_str());
  239.                 session_pool_.join(it->first, ss);
  240.                 ss->start();
  241.             }
  242.         }

  243.         void Client::handle_deadline(){

  244.             check_all();
  245.             if(!all_){
  246.                 logs.write_log(NORMAL, "Timers out, begin to connect other server");
  247.                 start_connect();    
  248.             }
  249.             deadline_.expires_from_now(boost::posix_time::seconds(DEADLINE));
  250.             deadline_.async_wait(boost::bind(&Client::handle_deadline, this));
  251.         }

  252.         void Client::check_all(){
  253.             for(Stats::iterator it = status_.begin(); it != status_.end(); it++){
  254.                 if(it->second < 0){
  255.                     all_ = false;
  256.                     return;    
  257.                 }    
  258.             }    
  259.             all_ = true;
  260.             return;

  261.         }

  262.     };
  263. };
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章