2014-06-18 124 views
1

我有一個tcp客戶端輪詢服務器的截止日期的答案,以便如果服務器無法到達客戶端不被阻止。我遇到的問題是,async_wait似乎永遠不會調用它的處理程序,當它無法連接時有效地阻止客戶端。每撥打tcpPoll都會有自己的線程(這就是爲什麼我創建了一個新的io_service),但即使沒有多線程,它也不起作用。而且,NetworkEntity對象在其生命週期內可以多次呼叫tcpPollboost :: asio :: deadline_timer不會調用處理程序

我的問題是:什麼阻止deadline_timer調用它的處理程序? (以及如何解決它)

下面是一些相關的代碼,這是工作,只要沒有失敗(連接,寫,讀)(抱歉,如果這是一個有點長):

void NetworkEntity::stop() 
{ 
    stopped_ = true; 
    //close socket 
    //cancel timeout 
} 

void NetworkEntity::check_timeout(const boost::system::error_code& error) 
{ 
    if (stopped_) 
     return; 
    if (timeout_.expires_at() <= boost::asio::deadline_timer::traits_type::now()) 
    { 
     stop(); 
     timeout_.expires_at(boost::posix_time::pos_infin); 
     std::cout << address_ << " timed out\n"; 
    } 
    timeout_.async_wait(boost::bind(&NetworkEntity::check_timeout, this, boost::asio::placeholders::error)); 
} 

std::vector<std::string> NetworkEntity::tcpPoll(const char* message, const char endOfMessage) 
{ 
    boost::asio::io_service io_service; 
    stopped_ = false; 
    timeout_.expires_from_now(boost::posix_time::seconds(TIMEOUT_)); 
    timeout_.async_wait(boost::bind(&NetworkEntity::check_timeout, this, boost::asio::placeholders::error)); 
    tcp::resolver resolver(io_service); 
    start_connect(&io_service, resolver.resolve(tcp::resolver::query(address_, port_)), message, endOfMessage); 
    io_service.run(); 
    //retrieve answer from class 
    //return answer 
} 

void NetworkEntity::start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endOfMessage) 
{ 
    socket_.reset(new tcp::socket(*io_service)); 
    socket_->async_connect(endpoint_iterator->endpoint(), 
     boost::bind(&NetworkEntity::handle_connect, this, io_service, boost::asio::placeholders::error, endpoint_iterator, message, endOfMessage)); 
} 

void NetworkEntity::handle_connect(boost::asio::io_service* io_service, const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endOfMessage) 
{ 
    if(stopped_) 
     return; 
    if (err) 
    { 
     std::cout << "Connect error: " << err.message() << "\n"; 
     stop(); 
    } 
    else 
    { 
     start_write(message, endOfMessage); 
    } 
} 

void NetworkEntity::start_write(const std::string message, const char endOfMessage) 
{ 
    std::ostream request_stream(&request_); 
    request_stream << message; 
    boost::asio::async_write(*socket_, request_, 
     boost::bind(&NetworkEntity::handle_write, this, boost::asio::placeholders::error, endOfMessage)); 
} 

void NetworkEntity::handle_write(const boost::system::error_code& error, const char endOfMessage) 
{ 
    if (stopped_) 
     return; 
    if (!error) 
    { 
     //sleep for 500ms to let time for the reciever to process info (had a bug on this one) 
     start_read(endOfMessage); 
    } 
    else 
    { 
     std::cout << "write error : " << error.message() << "\n"; 
     stop(); 
    } 
} 

void NetworkEntity::start_read(const char endOfMessage) 
{ 
    boost::asio::async_read_until(*socket_, answer_, endOfMessage, 
     boost::bind(&NetworkEntity::handle_read, this, boost::asio::placeholders::error)); 
} 

void NetworkEntity::handle_read(const boost::system::error_code& error) 
{ 
    if (stopped_) 
     return; 
    if (error) 
    { 
     std::cout << "read error : " << error.message() << "\n"; 
     stop(); 
    } 
    else 
    { 
     stop(); 
    } 
} 
+0

Pleeeeeeeeeeeeeease下次讓您的樣品自成一體嗎?這種錯誤可能很明顯。通過這種方式,我們花了很多時間'製作'io服務,deadline_timers,地址/端口值,「猜測」套接字將shared_ptr爲1(爲什麼?),並且request_/answer_(可能)是streambuf。最糟糕的是,我們根據自己的經驗來執行這些操作,而不一定是您真正做到了這一點(讓您更難以看出是什麼絆倒了您) – sehe

+0

注意!我將在下次 –

回答

2

我想您必須與io_service的多個實例混淆。

我認爲這是因爲在你的代碼中你永遠不會顯示你如何初始化timeout_。並且您用於連接的io_service實例僅在您的tcpPoll函數中實例化......這使我相信您意外地將註冊截止日期計時器註冊到單獨的io_service上,甚至您甚至沒有運行該計時器?

下面是實際工作的一個版本,指出:

  1. 它已經擺脫了stopped_布爾值,因爲它是不必要的,勢必混淆
  2. 看到如何檢測新實施的check_timeoutstop各種程序流程
  3. 完整的代碼,自包含的,只是您在問題中發佈的代碼的幾行代碼
#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 

using tcp = boost::asio::ip::tcp; 

struct NetworkEntity { 

    boost::asio::io_service io_service; 
    boost::asio::deadline_timer timeout_{io_service}; 
    std::string address_ = "localhost"; 
    std::string port_ = "6767"; 
    int TIMEOUT_   = 3; 
    boost::shared_ptr<tcp::socket> socket_; 
    boost::asio::streambuf request_, answer_; 

    void stop() 
    { 
     if (socket_) 
     { 
      socket_->cancel(); 
      socket_->close(); 
     } 
     timeout_.cancel(); 
     io_service.stop(); 
    } 

    void check_timeout(const boost::system::error_code& error) 
    { 
     if (error != boost::asio::error::operation_aborted) 
     { 
      stop(); 
      std::cout << address_ << " timed out\n"; 
     } 
     timeout_.async_wait(boost::bind(&NetworkEntity::check_timeout, this, boost::asio::placeholders::error)); 
    } 

    std::vector<std::string> tcpPoll(const char* message, const char endOfMessage) 
    { 
     timeout_.expires_from_now(boost::posix_time::seconds(TIMEOUT_)); 
     timeout_.async_wait(boost::bind(&NetworkEntity::check_timeout, this, boost::asio::placeholders::error)); 

     tcp::resolver resolver(io_service); 
     start_connect(&io_service, resolver.resolve(tcp::resolver::query(address_, port_)), message, endOfMessage); 

     io_service.run(); 
     //retrieve answer from class 
     //return answer 
     std::ostringstream oss; 
     oss << &answer_; 
     return { oss.str() }; 
    } 

    void start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endOfMessage) 
    { 
     socket_.reset(new tcp::socket(*io_service)); 
     socket_->async_connect(endpoint_iterator->endpoint(), 
       boost::bind(&NetworkEntity::handle_connect, this, io_service, boost::asio::placeholders::error, endpoint_iterator, message, endOfMessage)); 
    } 

    void handle_connect(boost::asio::io_service* io_service, 
      const boost::system::error_code& err, 
      tcp::resolver::iterator endpoint_iterator, 
      const std::string message, 
      const char endOfMessage) 
    { 
     if (err) 
     { 
      std::cout << "Connect error: " << err.message() << "\n"; 
      stop(); 
     } 
     else 
     { 
      start_write(message, endOfMessage); 
     } 
    } 

    void start_write(const std::string message, const char endOfMessage) 
    { 
     std::ostream request_stream(&request_); 
     request_stream << message; 
     boost::asio::async_write(*socket_, request_, 
       boost::bind(&NetworkEntity::handle_write, this, boost::asio::placeholders::error, endOfMessage)); 
    } 

    void handle_write(const boost::system::error_code& error, const char endOfMessage) 
    { 
     if (!error) 
     { 
      //sleep for 500ms to let time for the reciever to process info (had a bug on this one) 
      start_read(endOfMessage); 
     } 
     else 
     { 
      std::cout << "write error : " << error.message() << "\n"; 
      stop(); 
     } 
    } 

    void start_read(const char endOfMessage) 
    { 
     boost::asio::async_read_until(*socket_, answer_, endOfMessage, 
       boost::bind(&NetworkEntity::handle_read, this, boost::asio::placeholders::error)); 
    } 

    void handle_read(const boost::system::error_code& error) 
    { 
     if (error) 
     { 
      std::cout << "read error : " << error.message() << "\n"; 
     } 
     stop(); 
    } 
}; 

int main() 
{ 
    NetworkEntity ne; 
    for (auto& s : ne.tcpPoll("this is my request", '\n')) 
    { 
     std::cout << "Line: '" << s << "'\n"; 
    } 
} 
+0

我同意塞瑟先生,你不是一個阿西奧專家親愛的先生M__。 asio的學習曲線是有點強硬,該職位[鏈接](http://stackoverflow.com/questions/15568100/confused-when-boostasioio-service-run-method-blocks-unblocks?rq=1)可能會幫助你。 –

+0

我認爲你其實是對的,我正在使用我的主'io_service'在構造函數中初始化'timeout_'(我沒有顯示)。當我從一個'io_service'變成每個線程一個時,我沒有想到這一點。謝謝! –

相關問題