2017-01-30 5 views
0

다음 코드는 http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp의 부스트 문서 예제를 기반으로합니다. 방금 서버를 다른 스레드에서 실행하고 몇 초 동안 실행 한 후에 종료 할 수 있도록 조금 변경했습니다.부스트에서 메모리 누수 asio async tcp 에코 서버 예제

이 코드는 예상대로 작동합니다. 클라이언트가 연결하여 텍스트를 보내면 복사본이 클라이언트에 다시 표시됩니다.

한 가지 문제가 있습니다. 절대로 삭제되지 않는 클래스 session의 인스턴스가 하나 있습니다. 코드를 실행하면 생성자와 소멸자가 호출 된 횟수를 확인할 수 있습니다. 삭제되지 않는 것은 항상 session 인스턴스입니다.

이 문제를 해결할 수있는 간단한 방법이 있는지 궁금합니다. 아마도 나는 smart_ptr 클래스를 사용할 수 있습니다.

부스트 라이브러리 1.46을 사용해야합니다. 새로운 라이브러리 버전을 기반으로하는 몇 가지 다른 예제가 있습니다. 그러나 이러한 예는 구형 부스트 라이브러리에서 컴파일되지 않습니다. 문안 인사.

#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 즉 핸들러를 받아 들일 비동기로 전달되는 하나입니다. 나는 스마트 포인터를 사용하기 위해 많이 권할 것이다. 내가 즉 std::threadstd::shared_ptr 11 개 기능, C++의 사용을 만들었습니다

#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; 
} 

: shared_ptr 여기에 좋은 후보입니다. std::enable_shared_from_this은 개체를 만들 수 있습니다. this입니다. 그것은 session 클래스의 비동기 함수 호출 내에서 사용되는 방법을 점검하십시오.

또한 코드를 살펴보면 io_service::stop으로 전화하면 일부 오류 코드로 처리기가 호출 될 것으로 예상됩니다. 아니, 그건 사실이 아니야. 단순히 비동기 핸들러를 파괴하는 간단한 호출 scheduler::shutdown 일뿐입니다.

+0

도움 주셔서 감사합니다. – Peter