2017-01-30 78 views
0

以下代碼基於升壓文檔示例http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp。我只是稍微改了一點,以便我可以在不同的線程中運行服務器,並在運行幾秒鐘後退出。升壓asio異步tcp回顯服務器內存泄漏示例

此代碼按預期工作。當客戶端連接併發送一些文本時,副本會回傳給客戶端。

只有一個問題。有一個session類的實例永遠不會被刪除。如果您運行代碼,您可以見證構造函數和析構函數被調用的次數。它始終是最後一個不會被刪除的session實例。

想知道是否有一個簡單的方法來解決這個問題。也許我可以使用smart_ptr類。

請注意,我必須使用boost庫1.46。還有一些其他例子是基於更新的庫版本。但是這些例子在舊的boost庫中不能編譯。問候。

#include <cstdlib> 
#include <iostream> 
#include <vector> 
#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 

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

class session 
{ 
public: 
    session(boost::asio::io_service& io_service) 
    : socket_(io_service) 
    { 
    char buf[100]; sprintf(buf, "%p", this); 
    std::cout << "Session created: " << buf << std::endl; 
    } 

    ~session() { 
    char buf[100]; sprintf(buf, "%p", this); 
    std::cout << "Session destroyed: " << buf << std::endl; 
    } 

    tcp::socket& socket() 
    { 
    return socket_; 
    } 

    void start() 
    { 
    socket_.async_read_some(boost::asio::buffer(data_, max_length), 
     boost::bind(&session::handle_read, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_read(const boost::system::error_code& error, 
     size_t bytes_transferred) 
    { 
    if (!error) 
    { 
     boost::asio::async_write(socket_, 
      boost::asio::buffer(data_, bytes_transferred), 
      boost::bind(&session::handle_write, this, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     delete this; 
    } 
    } 

    void handle_write(const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     socket_.async_read_some(boost::asio::buffer(data_, max_length), 
      boost::bind(&session::handle_read, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    else 
    { 
     delete this; 
    } 
    } 

private: 
    tcp::socket socket_; 
    enum { max_length = 1024 }; 
    char data_[max_length]; 
}; 

class server 
{ 
public: 
    server(boost::asio::io_service& io_service, short port) 
    : io_service_(io_service), 
     acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) 
    { 
    session* new_session = new session(io_service_); 
    acceptor_.async_accept(new_session->socket(), 
     boost::bind(&server::handle_accept, this, new_session, 
      boost::asio::placeholders::error)); 
    } 

    ~server() { 
    } 

    void handle_accept(session* new_session, 
     const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     new_session->start(); // ownership passed 
     new_session = new session(io_service_); 
     acceptor_.async_accept(new_session->socket(), 
      boost::bind(&server::handle_accept, this, new_session, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error in HA: " << error.message() << std::endl; 
    } 
    } 

private: 
    boost::asio::io_service& io_service_; 
    tcp::acceptor acceptor_; 
}; 

/* 
int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 2) 
    { 
     std::cerr << "Usage: async_tcp_echo_server <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    using namespace std; // For atoi. 
    server s(io_service, atoi(argv[1])); 

    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
*/ 

static void serverThread(boost::asio::io_service* io_service) { 
    server s(*io_service, 5000); 
    io_service->run(); 
} 

int main(int argc, char* argv[]) 
{ 
    boost::asio::io_service io_service; 
    boost::thread t(serverThread, &io_service); 

    ::sleep(10); 
    io_service.stop(); 
    t.join(); 
    std::cout << "Quitting" << std::endl; 
    return 0; 
} 

回答

1

的一個沒有被刪除的是,被傳遞到異步接受處理程序即handler_accept之一。我會建議大量使用智能指針。 shared_ptr是一個很好的候選人在這裏:

#include <cstdlib> 
#include <iostream> 
#include <vector> 
#include <thread> 
#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <memory> 

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

class session: public std::enable_shared_from_this<session> 
{ 
public: 
    session(boost::asio::io_service& io_service) 
    : socket_(io_service) 
    { 
    char buf[100]; sprintf(buf, "%p", this); 
    std::cout << "Session created: " << buf << std::endl; 
    } 

    ~session() { 
    char buf[100]; sprintf(buf, "%p", this); 
    std::cout << "Session destroyed: " << buf << std::endl; 
    } 

    tcp::socket& socket() 
    { 
    return socket_; 
    } 

    void start() 
    { 
    socket_.async_read_some(boost::asio::buffer(data_, max_length), 
     boost::bind(&session::handle_read, shared_from_this(), 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_read(const boost::system::error_code& error, 
     size_t bytes_transferred) 
    { 
    if (!error) 
    { 
     boost::asio::async_write(socket_, 
      boost::asio::buffer(data_, bytes_transferred), 
      boost::bind(&session::handle_write, shared_from_this(), 
      boost::asio::placeholders::error)); 
    } 
    } 

    void handle_write(const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     socket_.async_read_some(boost::asio::buffer(data_, max_length), 
      boost::bind(&session::handle_read, shared_from_this(), 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    } 

private: 
    tcp::socket socket_; 
    enum { max_length = 1024 }; 
    char data_[max_length]; 
}; 

using session_ptr = std::shared_ptr<session>; 

class server 
{ 
public: 
    server(boost::asio::io_service& io_service, short port) 
    : io_service_(io_service), 
     acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) 
    { 
    auto new_session = std::make_shared<session>(io_service_); 
    acceptor_.async_accept(new_session->socket(), 
     boost::bind(&server::handle_accept, this, new_session, 
      boost::asio::placeholders::error)); 
    } 

    ~server() { 
    } 

    void handle_accept(session_ptr new_session, 
     const boost::system::error_code& error) 
    { 
    if (!error) 
    { 
     new_session->start(); // ownership passed 
     new_session.reset(); 
     new_session = std::make_shared<session>(io_service_); 
     acceptor_.async_accept(new_session->socket(), 
      boost::bind(&server::handle_accept, this, new_session, 
      boost::asio::placeholders::error)); 
    } 
    else 
    { 
     std::cout << "Error in HA: " << error.message() << std::endl; 
    } 
    } 

private: 
    boost::asio::io_service& io_service_; 
    tcp::acceptor acceptor_; 
}; 

/* 
int main(int argc, char* argv[]) 
{ 
    try 
    { 
    if (argc != 2) 
    { 
     std::cerr << "Usage: async_tcp_echo_server <port>\n"; 
     return 1; 
    } 

    boost::asio::io_service io_service; 

    using namespace std; // For atoi. 
    server s(io_service, atoi(argv[1])); 

    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 
*/ 

static void serverThread(boost::asio::io_service* io_service) { 
    server s(*io_service, 5000); 
    io_service->run(); 
} 

int main(int argc, char* argv[]) 
{ 
    boost::asio::io_service io_service; 
    std::thread t(serverThread, &io_service); 

    ::sleep(10); 
    io_service.stop(); 
    t.join(); 
    std::cout << "Quitting" << std::endl; 
    return 0; 
} 

我已經使用C++ 11點的特點,即std::threadstd::shared_ptrstd::enable_shared_from_this可讓您創建thisshared_ptr對象。檢查如何在session類的異步函數調用中使用它。

另外,看看代碼,它讓我覺得,你打電話給io_service::stop後,你會用一些錯誤代碼調用處理程序?不,情況並非如此。它將簡單地調用scheduler::shutdown,它只會破壞異步處理程序,沒有別的。

+0

謝謝你的幫助。 – Peter