我正在关注ASIO的async_tcp_echo_server.cpp示例来编写服务器。
我的服务器逻辑看起来像这样(.cpp部分):
1.Server startup:
bool Server::Start()
{
mServerThread = std::thread(&Server::ServerThreadFunc, this, std::ref(ios));
//ios is asio::io_service
}
2.Init acceptor并侦听传入连接:
void Server::ServerThreadFunc(io_service& service)
{
tcp::endpoint endp{ address::from_string(LOCAL_HOST),MY_PORT };
mAcceptor = acceptor_ptr(new tcp::acceptor{ service,endp });
// Add a job to start accepting connections.
StartAccept(*mAcceptor);
// Process event loop.Hang here till service terminated
service.run();
std::cout << "Server thread exiting." << std::endl;
}
3.接受连接并从客户端开始阅读:
void Server::StartAccept(tcp::acceptor& acceptor)
{
acceptor.async_accept([&](std::error_code err, tcp::socket socket)
{
if (!err)
{
std::make_shared<Connection>(std::move(socket))->StartRead(mCounter);
StartAccept(acceptor);
}
else
{
std::cerr << "Error:" << "Failed to accept new connection" << err.message() << std::endl;
return;
}
});
}
void Connection::StartRead(uint32_t frameIndex)
{
asio::async_read(mSocket, asio::buffer(&mHeader, sizeof(XHeader)), std::bind(&Connection::ReadHandler, shared_from_this(), std::placeholders::_1, std::placeholders::_2, frameIndex));
}
所以Connection实例最终触发ReadHandler
回调,我执行实际的读写操作:
void Connection::ReadHandler(const asio::error_code& error, size_t bytes_transfered, uint32_t frameIndex)
{
if (bytes_transfered == sizeof(XHeader))
{
uint32_t reply;
if (mHeader.code == 12345)
{
reply = (uint32_t)12121;
size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
}
else
{
reply = (uint32_t)0;
size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
this->mSocket.shutdown(tcp::socket::shutdown_both);
return;
}
}
while (mSocket.is_open())
{
XPacket packet;
packet.dataSize = rt->buff.size();
packet.data = rt->buff.data();
std::vector<asio::const_buffer> buffers;
buffers.push_back(asio::buffer(&packet.dataSize,sizeof(uint64_t)));
buffers.push_back(asio::buffer(packet.data, packet.dataSize));
auto self(shared_from_this());
asio::async_write(mSocket, buffers,
[this, self](const asio::error_code error, size_t bytes_transfered)
{
if (error)
{
ERROR(200, "Error sending packet");
ERROR(200, error.message().c_str());
}
}
);
}
}
现在,这是问题所在。服务器从客户端接收数据,并使用sync asio::write
发送,很好。但是当涉及到while循环中的asio::async_read
或asio::async_write
时,方法的lambda回调永远不会被触发,除非我在此之后立即放置io_context().run_one();
。我不明白为什么我会看到这种行为。我在acceptor init之后立即调用io_service.run()
,因此它会阻塞,直到服务器退出。据我所知,我的代码与asio示例的唯一区别在于我从自定义线程运行我的逻辑。
答案 0 :(得分:1)
您的回调未返回,阻止事件循环执行其他处理程序。
一般来说,如果你想要一个异步流程,你可以链接回调,例如回调检查./obj
,如果为true则调用is_open()
并将其自身作为回调。
在任何一种情况下,回调都会返回。
这允许事件循环运行,调用回调等等。
简而言之,您应确保异步回调始终在合理的时间范围内返回。