boost :: asio问题,将动态大小的数据传递给异步处理程序

时间:2019-04-26 08:29:45

标签: c++ sockets asynchronous boost asio

我正在处理带有Boost的自定义tcp数据包。由于所有操作都是异步的,因此必须调用处理程序来处理数据。主要问题是,在编译时未知大小时,我不知道如何将数据传递给处理程序? 例如,假设您收到标头字节,然后解析标头字节,它告诉您正文的长度:

int length = header.body_size();

我不知何故需要分配一个具有主体大小的数组,然后调用处理程序(这是一个类成员,而不是静态函数)并将数据传递给它。我该怎么做呢?

我尝试了各种不同的操作,例如,但总是遇到段错误,或者我不得不为body缓冲区提供固定大小,这不是我想要的。我的尝试可以在下面找到。

收到标头信息后:

char data[header.body_size()];
boost::asio::async_read(_socket, boost::asio::buffer(data, header.body_size()),
                                    boost::bind(&TCPClient::handle_read_body, this, boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred, data));

处理程序:

void TCPClient::handle_read_body(const boost::system::error_code &error, std::size_t bytes_transferred,
                                 const char *buffer) {

    Logger::log_info("Reading body. Body size: " + std::to_string(bytes_transferred));
}

此示例引发了段错误。

知道大小后如何为主体分配缓冲区? 然后我该如何调用处理程序并传递error_codebytes_transferred和主体数据?

一个示例代码片段将不胜感激,因为执行此操作的示例对我来说不是很清楚。

2 个答案:

答案 0 :(得分:2)

char data[header.body_size()];在C ++中不是标准的,一旦超出范围就会变得无效,而async_read要求缓冲区保持活动状态直到调用完成回调。因此,您可能应该在TCPClient上添加一个字段,其中包含等待接收的数据缓冲区列表(可能是std :: vector类型)。

答案 1 :(得分:0)

您需要做的就是在堆而不是堆栈上创建缓冲区。代替 VLA -char [sizeAtRuntime],您可以将std::stringstd::vectorstd::shared_ptr一起使用。通过使用string / vector,您可以将缓冲区设置为任意大小;通过使用shared_ptr,可以延长缓冲区的寿命。

带有bind的版本:

void foo()
{
    std::shared_ptr<std::vector<char>> buf = std::make_shared<std::vector<char>>(); // buf is local
    buf->resize( header.body_size() );
    // ditto with std::string

    boost::asio::async_read(_socket, boost::asio::buffer(*buf),
         boost::bind(&TCPClient::handle_read_body, 
                     this, boost::asio::placeholders::error,
                     boost::asio::placeholders::bytes_transferred, 
                     buf)); // buf is passed by value
}

void handle_read_body(const boost::system::error_code&, 
                      size_t, 
                      std::shared_ptr<std::vector<char>>)
{

}

在上面的示例中,buf被创建到堆栈上并指向向量到堆上,因为bind通过值获取其自变量,因此buf被复制并且引用计数器增加了-这意味着async_read结束且foo结束时,您的缓冲区仍然存在。

您可以使用lambda达到相同的行为,然后应按值捕获buf:

void foo()
{
    std::shared_ptr<std::vector<char>> buf = std::make_shared<std::vector<char>>(); // buf is local
    buf->resize( header.body_size() );
    // ditto with std::string

    boost::asio::async_read(_socket, boost::asio::buffer(*buf),
                                    boost::bind(&TCPClient::handle_read_body, this, boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred, buf)); // buf is passed by value

    boost::asio::async_read(_socket, boost::asio::buffer(*buf),
        [buf](const boost::system::error_code& , size_t)
         ^^^ capture buf by value, increates reference counter of shared_ptr
        {

        });
}