shared_from_this,asio上的弱弱ptr异常

时间:2018-04-05 15:40:58

标签: c++ shared-ptr asio

我知道这个问题已经在很多其他帖子中讨论过了。 特别是this似乎与我的问题类似,并且也处理了boost :: asio,但在我的情况下,我已经有了一个shared_ptr,它拥有调用shared_from_this()的对象

有什么想法吗?

这是代码

node.h

#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED

#include <vector>
#include <string>
#include <memory>
#include <thread>

#include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>

typedef boost::asio::ip::tcp::socket tcp_socket;
typedef boost::asio::ip::tcp::acceptor tcp_acceptor;
typedef std::shared_ptr<tcp_socket> tcp_socket_ptr;

class Peer;

class InConnection;
typedef std::shared_ptr<InConnection> InConnection_ptr;

class AsioNode
{
    friend class InConnection;

private:
    int _port;
    std::vector<Peer> _peers;

    std::vector<tcp_socket_ptr> _peers_connections;

    boost::asio::io_service _io_service;
    tcp_acceptor _acceptor;

    std::thread _rcv_thread;

    static const std::string inter_mex_delimiter;

    void accept();

    void handle_accept(InConnection_ptr new_connection, const boost::system::error_code &error);

public:
    AsioNode(const std::vector<Peer> &peers, int port);

    void initialize_telecom();
};

class InConnection: public boost::enable_shared_from_this<InConnection>
{
private:
    tcp_socket _input_socket;
    boost::asio::streambuf _input_buffer;

    void handle_read(const boost::system::error_code &error, std::size_t nbytes);

public:
    InConnection(boost::asio::io_service &svc) : _input_socket(svc){};

    tcp_socket &socket() {return _input_socket;}

    void read();
};

class Peer{
private:
    int _port;
    std::string _host;

public:
    Peer(std::string host, int port) : _host(host), _port(port) {}

    int get_port() const {return _port;}
    std::string get_host() const {return _host;}
};

typedef std::shared_ptr<AsioNode> AsioNode_ptr;

#endif // NODE_H_INCLUDED

node.cpp (在方法accept()中,对于每个连接,我创建一个新的InConnection对象并将其存储在shared_ptr上)

#include <vector>
#include <string>
#include <iostream>
#include <ostream>
#include <memory>
#include <exception>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "node.h"

void InConnection::read()
{
    boost::asio::async_read_until(_input_socket, _input_buffer, AsioNode::inter_mex_delimiter,
                                  boost::bind(&InConnection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void InConnection::handle_read(const boost::system::error_code &error, std::size_t nbytes)
{
    if(!error)
    {
        // do things

        read();
    }
    else
        std::cout << "error in read " << error << std::endl;
}

const std::string AsioNode::inter_mex_delimiter = "end_message";

AsioNode::AsioNode(const std::vector<Peer> &peers, int port) :
    _port(port), _peers(peers), _acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
    _rcv_thread([&] {boost::asio::io_service::work work(_io_service); _io_service.run();})
{
    accept();
}

void AsioNode::initialize_telecom()
{
    boost::asio::ip::tcp::resolver resolver(_io_service);

    // initialize the client side (for gossiping packets)
    for (const auto &peer : _peers)
    {
        tcp_socket_ptr new_socket(new tcp_socket(_io_service));
        boost::system::error_code ec;
        auto endpoint = resolver.resolve(boost::asio::ip::tcp::resolver::query(peer.get_host(), std::to_string(peer.get_port())));
        boost::asio::connect(*new_socket, endpoint, ec);

        if(ec)
            std::cout << "error on connetctin" << std::endl;
        else{
         //   std::cout << _port << " connected to " << peer.get_port() << std::endl;
        }
        _peers_connections.push_back(new_socket);
    }
}

void AsioNode::accept()
{
    /* 
    * HERE i create the shared_ptr to the tcp connection
    *
    *
    */ 
    InConnection_ptr new_connection(new InConnection(_io_service));
    _acceptor.async_accept(new_connection->socket(),
                           boost::bind(&AsioNode::handle_accept, this, new_connection, boost::asio::placeholders::error));
}

void AsioNode::handle_accept(InConnection_ptr new_connection, const boost::system::error_code &error)
{
    if(!error)
    {
        std::cout << _port << " accept " << new_connection->socket().remote_endpoint().port() << std::endl;
        // start accepting the peer messages
        new_connection->read();
    }
    else
        std::cout << _port << " error " << error << " on accept" << std::endl;

    // listen for new peer connections
    accept();
}

简单的演示测试 每个节点都接受一个端口上的连接,并连接到其他三个节点

#include <iostream>
#include <vector>
#include <string>

#include "node.h"

int main()
{
    std::string localhost("127.0.0.1");
    int port1 = 10000;int port2 = 10001;int port3 = 10002;
    Peer peer1(localhost, port1), peer2(localhost, port2), peer3(localhost, port3);
    std::vector<Peer> peers1({peer2, peer3}), peers2({peer1, peer3}), peers3({peer1, peer2});

    // initialize the server side
    auto node1 = std::make_shared<AsioNode>(peers1, port1);
    auto node2 = std::make_shared<AsioNode>(peers2, port2);
    auto node3 = std::make_shared<AsioNode>(peers3, port3);

    node1->initialize_telecom();
    node2->initialize_telecom();
    node3->initialize_telecom();

    while(1);
}

1 个答案:

答案 0 :(得分:0)

问题在于我混合命名空间 std(std :: shared_ptr)和boost(boost :: enable_shared_from_this)。

在我的情况下,我解决了从boost::enable_shared_from_this移动到std::enable_shared_from_this