问题描述
限时送ChatGPT账号..我正在学习 Boost::asio 和所有异步的东西.如何异步读取 std::string 类型的变量 user_
?Boost::asio::buffer(user_)
仅适用于 async_write()
,但不适用于 async_read()
.它适用于向量,那么它不适用于字符串的原因是什么?除了声明 char user_[max_len]
和使用 Boost::asio::buffer(user_, max_len)
之外,还有其他方法吗?
I'm learning Boost::asio and all that async stuff. How can I asynchronously read to variable user_
of type std::string? Boost::asio::buffer(user_)
works only with async_write()
, but not with async_read()
. It works with vector, so what is the reason for it not to work with string? Is there another way to do that besides declaring char user_[max_len]
and using Boost::asio::buffer(user_, max_len)
?
另外,从 boost::enable_shared_from_this<Connection>
继承并在 中使用
和 shared_from_this()
而不是 this
有什么意义>async_read()async_write()
?我在示例中看到了很多.
Also, what's the point of inheriting from boost::enable_shared_from_this<Connection>
and using shared_from_this()
instead of this
in async_read()
and async_write()
? I've seen that a lot in the examples.
这是我的代码的一部分:
Here is a part of my code:
class Connection
{
public:
Connection(tcp::acceptor &acceptor) :
acceptor_(acceptor),
socket_(acceptor.get_io_service(), tcp::v4())
{ }
void start()
{
acceptor_.get_io_service().post(
boost::bind(&Connection::start_accept, this));
}
private:
void start_accept()
{
acceptor_.async_accept(socket_,
boost::bind(&Connection::handle_accept, this,
placeholders::error));
}
void handle_accept(const boost::system::error_code& err)
{
if (err)
{
disconnect();
}
else
{
async_read(socket_, boost::asio::buffer(user_),
boost::bind(&Connection::handle_user_read, this,
placeholders::error, placeholders::bytes_transferred));
}
}
void handle_user_read(const boost::system::error_code& err,
std::size_t bytes_transferred)
{
if (err)
{
disconnect();
}
else
{
...
}
}
...
void disconnect()
{
socket_.shutdown(tcp::socket::shutdown_both);
socket_.close();
socket_.open(tcp::v4());
start_accept();
}
tcp::acceptor &acceptor_;
tcp::socket socket_;
std::string user_;
std::string pass_;
...
};
推荐答案
Boost.Asio 文档说明:
The Boost.Asio documentation states:
缓冲区对象将内存的连续区域表示为由指针和大小(以字节为单位)组成的 2 元组.{void*, size_t} 形式的元组指定可变(可修改)内存区域.
A buffer object represents a contiguous region of memory as a 2-tuple consisting of a pointer and size in bytes. A tuple of the form {void*, size_t} specifies a mutable (modifiable) region of memory.
这意味着为了调用 async_read
将数据写入缓冲区,它必须(在底层缓冲区对象中)是一个连续的内存块.此外,缓冲区对象必须能够写入该内存块.
This means that in order for a call to async_read
to write data to a buffer, it must be (in the underlying buffer object) a contiguous block of memory. Additionally, the buffer object must be able to write to that block of memory.
std::string
不允许任意写入其缓冲区,因此 async_read
不能将内存块写入字符串的缓冲区(注意 std::string
does 通过 data()
方法给予调用者对底层缓冲区的只读访问,这保证返回的指针在下一个调用非常量成员函数.因此,Asio 可以轻松创建一个 const_buffer
包装一个 std::string
,您可以将它与 async_write 一起使用
).
std::string
does not allow arbitrary writes into its buffer, so async_read
cannot write chunks of memory into a string's buffer (note that std::string
does give the caller read-only access to the underlying buffer via the data()
method, which guarantees that the returned pointer will be valid until the next call to a non-const member function. For this reason, Asio can easily create a const_buffer
wrapping an std::string
, and you can use it with async_write
).
Asio 文档有一个简单的聊天"程序的示例代码(参见 http://www.boost/doc/libs/1_43_0/doc/html/boost_asio/examples.html#boost_asio.examples.chat) 具有克服这个问题的好方法.基本上,您需要首先让发送 TCP 沿着消息的大小发送,在各种标头"中,并且您的读取处理程序必须解释标头以分配适合读取实际数据的固定大小的缓冲区.
The Asio documentation has example code for a simple "chat" program (see http://www.boost/doc/libs/1_43_0/doc/html/boost_asio/examples.html#boost_asio.examples.chat) that has a good method of overcoming this problem. Basically, you need to have the sending TCP send along the size of a message first, in a "header" of sorts, and your read handler must interpret the header to allocate a buffer of a fixed size suitable for reading the actual data.
至于在async_read
和async_write
中需要使用shared_from_this()
,原因是它保证了由boost::bind
将始终引用活动对象.考虑以下情况:
As far as the need for using shared_from_this()
in async_read
and async_write
, the reason is that it guarantees that the method wrapped by boost::bind
will always refer to a live object. Consider the following situation:
handle_accept
方法调用 async_read
并将处理程序发送到反应器"中 - 基本上您已经要求 io_service
调用 Connection::handle_user_read
当它完成从套接字读取数据时.io_service
存储这个函子并继续它的循环,等待异步读取操作完成.在您调用 async_read
之后,Connection
对象由于某种原因(程序终止、错误条件等)被释放假设 io_service
现在确定异步读取已完成,afterConnection
对象已被释放但之前em> io_service
被破坏(这可能发生,例如,如果 io_service::run
在单独的线程中运行,这是典型的).现在,io_service
尝试调用处理程序,但它对 Connection
对象的引用无效.
Your handle_accept
method calls async_read
and sends a handler "into the reactor" - basically you've asked the io_service
to invoke Connection::handle_user_read
when it finishes reading data from the socket. The io_service
stores this functor and continues its loop, waiting for the asynchronous read operation to complete.
After your call to async_read
, the Connection
object is deallocated for some reason (program termination, an error condition, etc.)
Suppose the io_service
now determines that the asynchronous read is complete, after the Connection
object has been deallocated but before the io_service
is destroyed (this can occur, for example, if io_service::run
is running in a separate thread, as is typical). Now, the io_service
attempts to invoke the handler, and it has an invalid reference to a Connection
object.
解决方案是通过shared_ptr
分配Connection
,发送时使用shared_from_this()
代替this
进入反应器"的处理程序 - 这允许 io_service
存储对对象的共享引用,并且 shared_ptr
保证在最后一个引用到期之前它不会被释放.
The solution is to allocate Connection
via a shared_ptr
and use shared_from_this()
instead of this
when sending a handler "into the reactor" - this allows io_service
to store a shared reference to the object, and shared_ptr
guarantees that it won't be deallocated until the last reference expires.
因此,您的代码应该类似于:
So, your code should probably look something like:
class Connection : public boost::enable_shared_from_this<Connection>
{
public:
Connection(tcp::acceptor &acceptor) :
acceptor_(acceptor),
socket_(acceptor.get_io_service(), tcp::v4())
{ }
void start()
{
acceptor_.get_io_service().post(
boost::bind(&Connection::start_accept, shared_from_this()));
}
private:
void start_accept()
{
acceptor_.async_accept(socket_,
boost::bind(&Connection::handle_accept, shared_from_this(),
placeholders::error));
}
void handle_accept(const boost::system::error_code& err)
{
if (err)
{
disconnect();
}
else
{
async_read(socket_, boost::asio::buffer(user_),
boost::bind(&Connection::handle_user_read, shared_from_this(),
placeholders::error, placeholders::bytes_transferred));
}
}
//...
};
请注意,您现在必须确保每个 Connection
对象都是通过 shared_ptr
分配的,例如:
Note that you now must make sure that each Connection
object is allocated via a shared_ptr
, e.g.:
boost::shared_ptr<Connection> new_conn(new Connection(...));
希望这有帮助!
这篇关于如何使用 Boost::asio 异步读取 std::string?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论