2012-02-09 23 views
5

एसिंक्रोनस बूस्ट एएसआईओ टीसीपी सर्वर को बंद करने का सही तरीका क्या है? मेरा वर्तमान समाधान आमतौर पर विनाशक में deadlocks। क्यूं कर?एएसआईओ टीसीपी सर्वर को सही तरीके से बंद कैसे करें?

class connection; 

typedef std::set<shared_ptr<connection>> connection_set; 

class connection : public enable_shared_from_this<connection> 
{  
    shared_ptr<tcp::socket>   socket_; 

    std::array<char, 8192>   data_; 

    shared_ptr<connection_set>  connection_set_; 
public: 
    static shared_ptr<connection> create(shared_ptr<tcp::socket> socket, shared_ptr<connection_set> connection_set) 
    { 
     auto con = shared_ptr<connection>(new connection(std::move(socket), std::move(connection_set))); 
     con->read_some(); 
     return con; 
    } 

    void on_next(const event& e) 
    { 
     // async_write_some ... 
    } 

private: 
    connection(shared_ptr<tcp::socket> socket, shared_ptr<connection_set> connection_set) 
     : socket_(std::move(socket)) 
     , connection_set_(std::move(connection_set)) 
    { 
    } 

    void handle_read(const boost::system::error_code& error, size_t bytes_transferred) 
    {  
     if(!error) 
     { 
      on_read(std::string(data_.begin(), data_.begin() + bytes_transferred));  
      read_some(); 
     } 
     else if (error != boost::asio::error::operation_aborted) 
      connection_set_->erase(shared_from_this()); 
     else 
      read_some(); 
    } 

    void handle_write(const shared_ptr<std::vector<char>>& data, const boost::system::error_code& error, size_t bytes_transferred) 
    { 
     if(!error)   
     { 
     } 
     else if (error != boost::asio::error::operation_aborted) 
      connection_set_->erase(shared_from_this()); 
    } 

    void read_some() 
    { 
     socket_->async_read_some(boost::asio::buffer(data_.data(), data_.size()), std::bind(&connection::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 
    } 

    void on_read(std::string str) 
    { 
     // parse the string... 
    } 
}; 

class tcp_observer 
{ 
    boost::asio::io_service    service_; 
    tcp::acceptor      acceptor_; 
    std::shared_ptr<connection_set>  connection_set_; 
    boost::thread      thread_; 

public: 
    tcp_observer(unsigned short port) 
     : acceptor_(service_, tcp::endpoint(tcp::v4(), port)) 
     , thread_(std::bind(&boost::asio::io_service::run, &service_)) 
    { 
     start_accept(); 
    } 

    ~tcp_observer() 
    { 
     // Deadlocks... 
     service_.post([=] 
     { 
      acceptor_.close(); 
      connection_set_->clear(); 
     }); 
     thread_.join(); 
    } 

    void on_next(const event& e) 
    { 
     service_.post([=] 
     { 
      BOOST_FOREACH(auto& connection, *connection_set_) 
       connection->on_next(e); 
     }); 
    } 
private:   
    void start_accept() 
    { 
     auto socket = std::make_shared<tcp::socket>(service_); 
     acceptor_.async_accept(*socket, std::bind(&tcp_observer::handle_accept, this, socket, std::placeholders::_1)); 
    } 

    void handle_accept(const shared_ptr<tcp::socket>& socket, const boost::system::error_code& error) 
    { 
     if (!acceptor_.is_open()) 
      return; 

     if (!error)  
      connection_set_->insert(connection::create(socket, connection_set_)); 

     start_accept(); 
    } 
}; 

उत्तर

3

यह "गतिरोध" क्योंकि कनेक्शन, नष्ट होने के लिए के बाद से वहाँ अभी भी संचालन जहां एक shared_from_this() पारित किया गया था लंबित हैं नहीं जा रहे हैं।

प्रत्येक कनेक्शन के सॉकेट शट डाउन (..) और बंद (..) पर कॉल करें। फिर पूरा होने की प्रतीक्षा करें जो या तो eof या operation_aborted संकेत करता है।

+0

क्या मैं सॉकेट शटडाउन को कॉल कर सकता हूं और किसी अन्य थ्रेड पर बंद कर सकता हूं? या यह io_service धागे में होना चाहिए? – ronag

+1

[टीसीपी सॉकेट दस्तावेज] के अनुसार (http://www.boost.org/doc/libs/1_48_0/doc/html/boost_asio/reference/ip__tcp/socket.html), एक्सेस को सिंक्रनाइज़ किया जाना चाहिए (या हर बार एक्सेस किया जाना चाहिए एक ही धागे से)। – Simon

संबंधित मुद्दे