[英]Asio: Prevent asynchronous client from being deleted?
I have the following code, trying to code an asynchronous client. 我有以下代码,尝试编写异步客户端。
The problem is that in main()
, the Client
gets deleted in the try-catch block, because execution leaves the scope. 问题在于在
main()
, Client
会在try-catch块中删除,因为执行会离开作用域。
I've tried to come up with a solution to this problem, like adding a while(true)
, but I don't like this approach. 我试图为这个问题提供解决方案,例如添加
while(true)
,但是我不喜欢这种方法。 Also, I don't prefer a getchar()
. 另外,我也不喜欢
getchar()
。
Due to the asynchronous nature of the calls, both connect()
and loop()
returns immediately. 由于调用的异步特性,
connect()
和loop()
立即返回。
How can I fix this? 我怎样才能解决这个问题?
#include <iostream>
#include <thread>
#include <string>
#include <boost\asio.hpp>
#include <Windows.h>
#define DELIM "\r\n"
using namespace boost;
class Client {
public:
Client(const std::string& raw_ip_address, unsigned short port_num) :
m_ep(asio::ip::address::from_string(raw_ip_address), port_num), m_sock(m_ios)
{
m_work.reset(new asio::io_service::work(m_ios));
m_thread.reset(new std::thread([this]() {
m_ios.run();
}));
m_sock.open(m_ep.protocol());
}
void connect()
{
m_sock.async_connect(m_ep, [this](const system::error_code& ec)
{
if (ec != 0) {
std::cout << "async_connect() error: " << ec.message() << " (" << ec.value() << ") " << std::endl;
return;
}
std::cout << "Connection to server has been established." << std::endl;
});
}
void loop()
{
std::thread t = std::thread([this]()
{
recv();
});
t.join();
}
void recv()
{
asio::async_read_until(m_sock, buf, DELIM, [this](const system::error_code& ec, std::size_t bytes_transferred)
{
if (ec != 0) {
std::cout << "async_read_until() error: " << ec.message() << " (" << ec.value() << ") " << std::endl;
return;
}
std::istream is(&buf);
std::string req;
std::getline(is, req, '\r');
is.get(); // discard newline
std::cout << "Received: " << req << std::endl;
if (req == "alive") {
recv();
}
else if (req == "close") {
close();
return;
}
else {
send(req + DELIM);
}
});
}
void send(std::string resp)
{
auto s = std::make_shared<std::string>(resp);
asio::async_write(m_sock, asio::buffer(*s), [this, s](const system::error_code& ec, std::size_t bytes_transferred)
{
if (ec != 0) {
std::cout << "async_write() error: " << ec.message() << " (" << ec.value() << ") " << std::endl;
return;
}
else {
recv();
}
});
}
void close()
{
m_sock.close();
m_work.reset();
m_thread->join();
}
private:
asio::io_service m_ios;
asio::ip::tcp::endpoint m_ep;
asio::ip::tcp::socket m_sock;
std::unique_ptr<asio::io_service::work> m_work;
std::unique_ptr<std::thread> m_thread;
asio::streambuf buf;
};
int main()
{
const std::string raw_ip_address = "127.0.0.1";
const unsigned short port_num = 8001;
try {
Client client(raw_ip_address, port_num);
client.connect();
client.loop();
}
catch (system::system_error &err) {
std::cout << "main() error: " << err.what() << " (" << err.code() << ") " << std::endl;
return err.code().value();
}
return 0;
}
You've not really understood how asio works. 您还不太了解asio的工作原理。 Typically in the main thread(s) you will call
io_service::run()
(which will handle all the asynchronous events.) 通常,在主线程中,您将调用
io_service::run()
(它将处理所有异步事件。)
To ensure the lifetime of the Client
, use a shared_ptr<>
and ensure this shared pointer is used in the handlers. 为了确保
Client
的生命周期,请使用shared_ptr<>
并确保在处理程序中使用此共享指针。 For example.. 例如..
io_service service;
{
// Create the client - outside of this scope, asio will manage
// the life time of the client
auto client = make_shared<Client>(service);
client->connect(); // setup the connect operation..
}
// Now run the io service event loop - this will block until there are no more
// events to handle
service.run();
Now you need to refactor your Client
code: 现在,您需要重构
Client
代码:
class Client : public std::enable_shared_from_this<Client> {
Client(io_service& service): socket_(service) ...
{ }
void connect() {
// By copying the shared ptr to the lambda, the life time of
// Client is guaranteed
socket_.async_connect(endpoint_, [self = this->shared_from_this()](auto ec)
{
if (ec) {
return;
}
// Read
self->read(self);
});
}
void read(shared_ptr<Client> self) {
// By copying the shared ptr to the lambda, the life time of
// Client is guaranteed
asio::async_read_until(socket_, buffer_, DELIM, [self](auto ec, auto size)
{
if (ec) {
return;
}
// Handle the data
// Setup the next read operation
self->read(self)
});
}
};
You have a thread for the read operation - which is not necessary. 您具有用于读取操作的线程-这不是必需的。 That will register one async read operation and return immediately.
这将注册一个异步读取操作并立即返回。 You need to register a new read operation to continue reading the socket (as I've sketched out..)
您需要注册一个新的读取操作才能继续读取套接字(如我所概述的。)
You can post any function to io_service via post(Handler) http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/io_service/post.html 您可以通过post(Handler)将任何函数发布到io_service上http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/io_service/post.html
Then in the main() do something like: 然后在main()中执行以下操作:
while (!exit) {
io_service.run_one();
}
Or call io_service::run_one or io_service::run in the main() 或在main()中调用io_service :: run_one或io_service :: run
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.