我一直在研究 Boost.Asio 和 Boost.Beast 并且對何時需要使用socket::async_*成員函式呼叫進行顯式鏈包裝有一些困惑。
在 Boost.Asio (1.78) 中,有一個make_strand函式。Boost.Beast 提供的示例顯示它的使用方式如下:
服務器/聊天多/listener.cpp
void
listener::
run()
{
// The new connection gets its own strand
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
//...
// Handle a connection
void
listener::
on_accept(beast::error_code ec, tcp::socket socket)
{
if(ec)
return fail(ec, "accept");
else
// Launch a new session for this connection
boost::make_shared<http_session>(std::move(socket), state_)->run();
// The new connection gets its own strand
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
服務器/聊天多/http_session.cpp
void
http_session::
run()
{
do_read();
}
//...
void
http_session::
do_read()
{
// Construct a new parser for each message
parser_.emplace();
// Apply a reasonable limit to the allowed size
// of the body in bytes to prevent abuse.
parser_->body_limit(10000);
// Set the timeout.
stream_.expires_after(std::chrono::seconds(30));
// Read a request
http::async_read(
stream_,
buffer_,
parser_->get(),
beast::bind_front_handler(
&http_session::on_read,
shared_from_this()));
}
void
http_session::
on_read(beast::error_code ec, std::size_t)
{
// This means they closed the connection
if(ec == http::error::end_of_stream)
{
stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
return;
}
// Handle the error, if any
if(ec)
return fail(ec, "read");
// See if it is a WebSocket Upgrade
if(websocket::is_upgrade(parser_->get()))
{
// Create a websocket session, transferring ownership
// of both the socket and the HTTP request.
boost::make_shared<websocket_session>(
stream_.release_socket(),
state_)->run(parser_->release());
return;
}
//...
}
服務器/chat-multi/websocket_session.cpp
void
websocket_session::
on_read(beast::error_code ec, std::size_t)
{
// Handle the error, if any
if(ec)
return fail(ec, "read");
// Send to all connections
state_->send(beast::buffers_to_string(buffer_.data()));
// Clear the buffer
buffer_.consume(buffer_.size());
// Read another message
ws_.async_read(
buffer_,
beast::bind_front_handler(
&websocket_session::on_read,
shared_from_this()));
}
在同一個 Boost.Beast 示例中,對套接字async_read成員函式的后續呼叫是在沒有顯式地將作業包裝在一個鏈中的情況下完成的,通過post, dispatch(with socket::get_executor) 或用 包裝完成處理程式strand::wrap。
Based on the answer to this question, it seems that the make_strand function copies the executor into the socket object, and by default the socket object's completion handlers will be invoked on the same strand. Using socket::async_receive as an example, this to me says that there are two bits of work to be done:
A) The socket::async_receive I/O work itself
B) The work involved in calling the completion handler
My questions are:
According to the linked answer, when using
make_strandB is guaranteed to be called on the same strand, but not A. Is this correct, or have I misunderstood something?If 1) is correct, why does the server/chat-multi example provided above not explicitly wrap the
async_readwork on a strand?In Michael Caisse's cppcon 2016 talk, "Asynchronous IO with Boost.Asio", he also does not explicitly wrap
async_read_untiloperations in a strand. He explains that write calls should be synchronised with a strand, as they can in theory be called from any thread in the application. But read calls don't, as he is controlling them himself. How does this fit into the picture?
Thanks in advance
uj5u.com熱心網友回復:
如果未指定或系結執行程式,則使用“關聯執行程式”。
對于成員異步啟動函式,默認執行程式是來自 IO 物件的執行程式。在您的情況下,它將是在鏈執行器上(使用)創建的套接字。換句話說,socket.get_executor()已經回傳了strand<> 執行器。
只有在發布時,您才需要指定鏈執行器(或將處理程式系結到它,因此它成為處理程式的隱式默認值):
- 什么時候必須將 io_context 傳遞給 boost::asio::spawn?(C )
- 為什么 boost::asio::io 服務被設計為用作引數?
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/387206.html
標籤:c sockets boost boost-asio
