我正在处理带有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_code
,bytes_transferred
和主体数据?
一个示例代码片段将不胜感激,因为执行此操作的示例对我来说不是很清楚。
答案 0 :(得分:2)
char data[header.body_size()];
在C ++中不是标准的,一旦超出范围就会变得无效,而async_read
要求缓冲区保持活动状态直到调用完成回调。因此,您可能应该在TCPClient
上添加一个字段,其中包含等待接收的数据缓冲区列表(可能是std :: vector类型)。
答案 1 :(得分:0)
您需要做的就是在堆而不是堆栈上创建缓冲区。代替 VLA -char [sizeAtRuntime]
,您可以将std::string
或std::vector
与std::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
{
});
}