C ++ / Asio:使用async_write

问题描述

我正在使用Asio来处理我的网络课程。 我已经困扰了一段时间,但我不知道为什么。

首先,代码

// .h
#pragma once

#include <asio.hpp>

class Connection : public std::enable_shared_from_this<Connection>
{
public:
    static std::shared_ptr<Connection> create(asio::io_context& IoContext);
    asio::ip::tcp::socket& getSocket();
    void start();

private:
    Connection(asio::io_context& IoContext);
    void startReading();
    void sendPacket(std::string Packet);
    void handle_read(const asio::error_code& error,size_t bytes);
    void handle_write(const asio::error_code& error,size_t bytes);
    void disconnect();

    asio::ip::tcp::socket socket;
    char packet[4096];
    bool started;
};

class Network
{
public:
    Network(asio::io_context& IoContext,unsigned short Port);
    void startServer();

private:
    void startAccept();
    void handle_accept(std::shared_ptr<Connection> connection,const asio::error_code& error);

    asio::io_context& ioContext;
    asio::ip::tcp::acceptor acceptor;
    bool started;
    std::vector<std::shared_ptr<Connection>> connections;
};
// .cpp

Connection::Connection(asio::io_context& IoContext)
    : socket(IoContext),started(false),packet("")
{

}

std::shared_ptr<Connection> Connection::create(asio::io_context& IoContext)
{
    return std::shared_ptr<Connection>(new Connection(IoContext));
}

asio::ip::tcp::socket& Connection::getSocket()
{
    return socket;
}

void Connection::start()
{
    std::cout << "Connection::start();" << std::endl;
    if (!started)
    {
        startReading();
        started = true;
    }
}

void Connection::sendPacket(std::string Packet)
{
    socket.async_send(asio::buffer(Packet),[this](const asio::error_code& error,size_t bytes)
        { handle_write(error,bytes); });
}

void Connection::startReading()
{
    socket.async_receive(asio::buffer(packet),size_t bytes)
        { handle_read(error,bytes); });
}

void Connection::handle_write(const asio::error_code& error,size_t bytes)
{
    std::cout << "WRITE : " << error.message() << " size : " << bytes << std::endl;
}

void Connection::handle_read(const asio::error_code& error,size_t bytes)
{
    if (error)
    {
        std::cout << "error:" << error.message();
        disconnect();
    }
    else
    {
        if (bytes > 0)
        {
            packet[bytes] = 0;
            std::string response = ...;
            sendPacket(response);
        }
    }
}


Network::Network(asio::io_context& IoContext,unsigned short Port)
    : ioContext(IoContext),acceptor(ioContext,asio::ip::tcp::endpoint(asio::ip::tcp::v4(),Port)),started(false)
{
    std::cout << "Server::Server();" << std::endl;
}

void Network::startServer()
{
    std::cout << "Server::startServer();" << std::endl;
    if (!started)
    {
        startAccept();
        started = true;
    }
}

void Network::startAccept()
{
    std::cout << "Server::startAccept();" << std::endl;
    std::shared_ptr<Connection> connection = Connection::create(ioContext);
    connections.push_back(connection);
    asio::error_code er;
    acceptor.async_accept(connection->getSocket(),std::bind(&Network::handle_accept,this,connection,er));
}

void Network::handle_accept(std::shared_ptr<Connection> connection,const asio::error_code& error)
{
    std::cout << "Server::handle_accept();" << std::endl;
    if (!error)
    {
        std::cout << "Ok" << std::endl;
        connection->start();
    }
    startAccept();
}

(我从cpp中删除了不必要的功能,以使其更加简洁,如果缺少某些内容,请不要感到惊讶)

基本上,当我从handle_read函数sendPacket(something)崩溃时,它会崩溃。 我找到了两个解决方法

  • 创建并使用成员std::string,然后handle_read(...)中的代码变为
if (bytes > 0)
{
    packet[bytes] = 0;
    std::string response = ...;
    sendPacket(my_member_string);
}
  • 我在std::string*中创建一个sendPacket(...)
void Connection::sendPacket(std::string Packet)
{
    std::string *copy;
    socket.async_send(asio::buffer(copy),bytes); });
}

删除它(如果这样做,它会以相同的方式崩溃)。

所以,我的问题是:response为什么引起崩溃?我读过很多关于“生命周期”的文章,您能告诉我更多吗? response一生中的这段代码中真正发生了什么? 另外,如果不是上述方法之一,那么解决错误的干净方法是什么?

顺便说一句,我使用Boost。

先谢谢您

解决方法

不应使用 ..._ async 函数在您的lambda中捕获[this]指针。因为lambda将超过 this 指针,而 this 将指向lambda调用中的无效地址。

使用[self=shared_from_this()]并在lambda中与 self 一起使用,这样该对象将通过异步调用与共享指针一起使用。