如何异步读取到std使用boost ::支持ASIO :: string的? [英] How to asynchronously read to std::string using Boost::asio?
问题描述
我学习的boost :: ASIO和所有的东西异步。我怎么可以异步读取类型为std变量用户_
:: string的? 的boost :: ASIO ::缓冲区(用户_)
仅 async_write作品()
,但不能与 async_read()
。它与载体,那么什么是它不与字符串工作的原因吗?是否有另一种方式做到这一点,除了宣告字符用户_ [MAX_LEN]
,并使用的boost :: ASIO ::缓冲区(用户_,MAX_LEN)
?
此外,什么是从升压继承:: enable_shared_from_this&LT点;连接>
,并使用 shared_from_this()
而不是的这个
在 async_read()
和 async_write()
?我已经看到了很多例子。
下面是我的code的一部分:
类连接
{
上市: 连接(TCP ::受体&放大器;受体):
acceptor_(受体),
socket_(acceptor.get_io_service(),TCP :: V4())
{} 无效的start()
{
acceptor_.get_io_service()后(
提高::绑定(安培;连接:: start_accept,这一点));
} 私人的: 无效start_accept()
{
acceptor_.async_accept(socket_,
提高::绑定(安培;连接:: handle_accept,为此,
占位符::错误));
} 无效handle_accept(常量的boost ::系统::错误_ code和;犯错)
{
如果(ERR)
{
断开();
}
其他
{
async_read(socket_,提高:: ASIO ::缓冲区(用户_),
提高::绑定(安培;连接:: handle_user_read,为此,
占位符::错误,占位符:: bytes_transferred));
}
} 无效handle_user_read(常量的boost ::系统::错误_ code和;错了,
的std ::为size_t bytes_transferred)
{
如果(ERR)
{
断开();
}
其他
{
...
}
} ... 无效断开()
{
socket_.shutdown(TCP ::插座:: shutdown_both);
socket_.close();
socket_.open(TCP :: V4());
start_accept();
} TCP ::受体和放大器; acceptor_;
TCP ::插座socket_;
标准::字符串用户_;
标准::字符串pass_;
...
};
该Boost.Asio的文档状态:
一个缓冲对象再presents一个连续的内存区域组成,以字节为指针和大小的2元组。表格{无效*,为size_t}的元组指定的内存可变(修改)区域。
块引用>这意味着为了调用
async_read
将数据写入到一个缓冲区,它必须是(在底层缓冲区对象)一个连续的内存块。此外,缓冲对象必须能够写入该存储器块。
的std :: string的
不允许随意写入其缓冲区,所以async_read
不能写的内存块成字符串的缓冲区(请注意,的std :: string的
的确实的通过给下面的缓冲来电只读访问数据()
方法,它保证了返回的指针将是有效的,直到一个非const成员函数的一个电话。出于这个原因,短耳可以很容易地创建一个const_buffer
包装的的std ::字符串
,你可以用async_write
)。使用p>该短耳文档有一个简单的聊天节目例如code(请参阅http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/examples.html#boost_asio.examples.chat)有解决这个问题的一个好方法。基本上,你需要有发送TCP沿着消息的大小发送首先,在各种各样的头,而你读的处理程序必须跨preT头分配固定大小的缓冲区适合于读出的实际数据。
至于需要使用
shared_from_this()
在async_read
和async_write
,其原因就在于它保证了通过的boost ::绑定
总是引用现场的对象。考虑以下情况:
- 您
handle_accept
的方法调用async_read
并发送处理程序进入反应器 - 基本上你问io_service对象
调用连接:: handle_user_read
当它完成从插座中读取数据。在io_service对象
商店函子,并继续循环,等待异步读取操作来完成。- 您调用
async_read
之后,连接
对象被释放某种原因(程序结束,故障状态等)- 假设
io_service对象
现在确定异步读取完成后,的之后的的连接
对象已经被释放,但的前的的io_service对象
被破坏(这可能发生,例如,如果io_service对象::运行
在单独的线程中运行,为的是典型的)。现在,io_service对象
试图调用处理程序,它有一个无效引用连接
对象。解决的办法是分配
连接
通过的shared_ptr
,并使用shared_from_this()
而不是这个
发送处理程序进入反应器的时候 - 这使得io_service对象
存储一个共享的参考对象,而的shared_ptr
保证直到最后一个引用到期,便不会被释放。所以,你的code或许应该是这个样子:
类连接:公众的boost :: enable_shared_from_this<连接GT&;
{
上市: 连接(TCP ::受体&放大器;受体):
acceptor_(受体),
socket_(acceptor.get_io_service(),TCP :: V4())
{} 无效的start()
{
acceptor_.get_io_service()后(
提高::绑定(安培;连接:: start_accept,shared_from_this()));
}私人的: 无效start_accept()
{
acceptor_.async_accept(socket_,
提高::绑定(安培;连接:: handle_accept,shared_from_this()
占位符::错误));
} 无效handle_accept(常量的boost ::系统::错误_ code和;犯错)
{
如果(ERR)
{
断开();
}
其他
{
async_read(socket_,提高:: ASIO ::缓冲区(用户_),
提高::绑定(安培;连接:: handle_user_read,shared_from_this()
占位符::错误,占位符:: bytes_transferred));
}
}
// ...
};请注意,你现在必须确保每个
连接
对象是通过的shared_ptr
,例如分配的:的boost :: shared_ptr的<连接GT&; new_conn(新连接(...));
希望这有助于!
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 withasync_write()
, but not withasync_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 declaringchar user_[max_len]
and usingBoost::asio::buffer(user_, max_len)
?Also, what's the point of inheriting from
boost::enable_shared_from_this<Connection>
and usingshared_from_this()
instead ofthis
inasync_read()
andasync_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_; ... };
解决方案The Boost.Asio documentation states:
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.
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
does not allow arbitrary writes into its buffer, soasync_read
cannot write chunks of memory into a string's buffer (note thatstd::string
does give the caller read-only access to the underlying buffer via thedata()
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 aconst_buffer
wrapping anstd::string
, and you can use it withasync_write
).The Asio documentation has example code for a simple "chat" program (see http://www.boost.org/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.
As far as the need for using
shared_from_this()
inasync_read
andasync_write
, the reason is that it guarantees that the method wrapped byboost::bind
will always refer to a live object. Consider the following situation:
- Your
handle_accept
method callsasync_read
and sends a handler "into the reactor" - basically you've asked theio_service
to invokeConnection::handle_user_read
when it finishes reading data from the socket. Theio_service
stores this functor and continues its loop, waiting for the asynchronous read operation to complete.- After your call to
async_read
, theConnection
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 theConnection
object has been deallocated but before theio_service
is destroyed (this can occur, for example, ifio_service::run
is running in a separate thread, as is typical). Now, theio_service
attempts to invoke the handler, and it has an invalid reference to aConnection
object.The solution is to allocate
Connection
via ashared_ptr
and useshared_from_this()
instead ofthis
when sending a handler "into the reactor" - this allowsio_service
to store a shared reference to the object, andshared_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)); } } //... };
Note that you now must make sure that each
Connection
object is allocated via ashared_ptr
, e.g.:boost::shared_ptr<Connection> new_conn(new Connection(...));
Hope this helps!
这篇关于如何异步读取到std使用boost ::支持ASIO :: string的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!