C++ 使用队列将asio异步读写提升到套接字

C++ 使用队列将asio异步读写提升到套接字,c++,boost,boost-asio,C++,Boost,Boost Asio,我正在一个简单的TCP服务器上工作,它可以将消息读写到线程安全队列。然后,应用程序可以使用这些队列安全地读取和写入套接字,即使来自不同的线程 我面临的问题是,我无法异步读取。我的队列具有pop操作,该操作返回下一个要处理的元素,但如果没有可用的元素,它将阻塞。因此,一旦我调用pop,async\u read回调当然不再被触发。有没有一种方法可以将这样的队列集成到boost asio中,或者我必须完全重写 下面是我做的一个简短的例子来说明我的问题。建立TCP连接后,我将创建一个新线程,该线程将在该

我正在一个简单的TCP服务器上工作,它可以将消息读写到线程安全队列。然后,应用程序可以使用这些队列安全地读取和写入套接字,即使来自不同的线程

我面临的问题是,我无法
异步读取
。我的队列具有
pop
操作,该操作返回下一个要处理的元素,但如果没有可用的元素,它将阻塞。因此,一旦我调用pop,
async\u read
回调当然不再被触发。有没有一种方法可以将这样的队列集成到boost asio中,或者我必须完全重写

下面是我做的一个简短的例子来说明我的问题。建立TCP连接后,我将创建一个新线程,该线程将在该TCP_连接下运行应用程序。然后我想开始
async\u读取
async\u写入
。几个小时来,我一直在想这个问题,我真的不知道如何解决这个问题

class tcp_connection : public std::enable_shared_from_this<tcp_connection>
{
public:
    static std::shared_ptr<tcp_connection> create(boost::asio::io_service &io_service) {
        return std::shared_ptr<tcp_connection>(new tcp_connection(io_service));
    }

    boost::asio::ip::tcp::socket& get_socket()
    {
        return this->socket;
    }

    void app_start()
    {
        while(1)
        {
            // Pop is a blocking call.
            auto inbound_message = this->inbound_messages.pop();
            std::cout << "Got message in app thread: " << inbound_message << ". Sending it back to client." << std::endl;
            this->outbound_messages.push(inbound_message);
        }
    }

    void start() {
        this->app_thread = std::thread(&tcp_connection::app_start, shared_from_this());

        boost::asio::async_read_until(this->socket, this->input_stream, "\r\n",
            strand.wrap(boost::bind(&tcp_connection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));

        // Start async writing here. The message to send are in the outbound_message queue. But a Pop operation blocks
        // empty() is also available to check whether the queue is empty.
        // So how can I async write without blocking the read.
        // block...
        auto message = this->outbound_messages.pop();
        boost::asio::async_write(this->socket, boost::asio::buffer(message),
            strand.wrap(boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
    }

    void handle_read(const boost::system::error_code& e, size_t bytes_read)
    {
        std::cout << "handle_read called" << std::endl;
        if (e)
        {
            std::cout << "Error handle_read: " << e.message() << std::endl;
            return;
        }
        if (bytes_read != 0)
        {
            std::istream istream(&this->input_stream);
            std::string message;
            message.resize(bytes_read);
            istream.read(&message[0], bytes_read);
            std::cout << "Got message: " << message << std::endl;
            this->inbound_messages.push(message);
        }
        boost::asio::async_read_until(this->socket, this->input_stream, "\r\n",
            strand.wrap(boost::bind(&tcp_connection::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
    }

    void handle_write(const boost::system::error_code& e, size_t /*bytes_transferred*/)
    {
        if (e)
        {
            std::cout << "Error handle_write: " << e.message() << std::endl;
            return;
        }

        // block...
        auto message = this->outbound_messages.pop();
        boost::asio::async_write(this->socket, boost::asio::buffer(message),
            strand.wrap(boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
    }



private:
    tcp_connection(boost::asio::io_service& io_service) : socket(io_service), strand(io_service)
    {
    }

    boost::asio::ip::tcp::socket socket;
    boost::asio::strand strand;
    boost::asio::streambuf input_stream;

    std::thread app_thread;

    concurrent_queue<std::string> inbound_messages;
    concurrent_queue<std::string> outbound_messages;
};

class tcp_server
{
public:
    tcp_server(boost::asio::io_service& io_service)
        : acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 9001))
    {
        start_accept();
    }

private:
    void start_accept()
    {
        std::shared_ptr<tcp_connection> new_connection =
            tcp_connection::create(acceptor.get_io_service());

        acceptor.async_accept(new_connection->get_socket(),
            boost::bind(&tlcp_tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error));
    }

    void handle_accept(std::shared_ptr<tcp_connection> new_connection,
                       const boost::system::error_code& error)
    {
        if (!error)
        {
            new_connection->start();
        }

        start_accept();
    }

    boost::asio::ip::tcp::acceptor acceptor;
};
class-tcp\u连接:public-std::从\u中启用\u共享\u
{
公众:
静态std::共享ptr创建(boost::asio::io_服务和io_服务){
返回std::shared_ptr(新tcp_连接(io_服务));
}
boost::asio::ip::tcp::socket和get_socket()
{
返回此->套接字;
}
无效应用程序_开始()
{
而(1)
{
//Pop是一个阻塞呼叫。
自动入站消息=此->入站消息.pop();
std::无法输入\u流“\r\n”,
wrap(boost::bind(&tcp_connection::handle_read,shared_from_this(),boost::asio::placeholders::error,boost::asio::placeholders::bytes_transfer));
//在此处开始异步写入。要发送的消息位于出站消息队列中。但Pop操作会阻塞
//empty()还可用于检查队列是否为空。
//那么,如何在不阻塞读取的情况下进行异步写入呢。
//阻止。。。
自动消息=此->出站消息.pop();
boost::asio::async_write(这个->套接字,boost::asio::buffer(消息),
wrap(boost::bind(&tcp_connection::handle_write,shared_from_this(),boost::asio::placeholders::error,boost::asio::placeholders::bytes_transfer));
}
无效句柄读取(const boost::system::error\u code&e,size\u t bytes\u read)
{

std::cout在我看来,似乎您需要一个
异步\u-pop
方法,该方法采用错误消息占位符和回调处理程序。当您收到消息时,检查是否有未完成的处理程序,如果有,则弹出消息,取消注册处理程序并调用它。同样,在注册异步\u-pop时,如果已经有消息等待,弹出消息并向处理程序发出一个调用,而不进行注册


您可能希望从类型为
pop\u operation
或类似的多态基类派生async\u pop类。

在我看来,您似乎需要一个
async\u pop
方法,该方法采用错误消息占位符和回调处理程序。当您收到消息时,请检查是否有未完成的处理程序,如果有,请弹出同样,在注册async_pop时,如果已经有消息等待,则弹出消息并向处理程序发出调用,而不注册它


您可能希望从类型为
pop\u operation
或类似的多态基类派生async\u pop类。

谢谢!我没有想到我可以自己创建这样的处理程序。正如我使用的
strand.wrap
一样,这应该可以正常工作。但我有一个问题,为什么我需要错误消息占位符?@JohnSmith my error.您需要一个消息占位符(std::string&?)如果消息队列已耗尽且存在读取错误,您将希望将上次不成功io读取操作中的any错误代码传递回异步处理程序。是的,我现在已经实现了它。在代码中,它不是字符串,但用示例字符串演示是最简单的。Tommorow我将在另一个ans中发布代码wer,但我会将您的保留为已接受。仅适用于对相同内容感到疑惑的人。谢谢!我没有想到我可以自己创建这样的处理程序。正如我使用的
strand.wrap一样,这应该可以正常工作。但我有一个问题是,为什么我需要错误消息占位符?@JohnSmith my error。您需要一个消息位置保持器(标准::字符串和?)如果消息队列已耗尽且存在读取错误,您将希望将上次不成功io读取操作中的any错误代码传递回异步处理程序。是的,我现在已经实现了它。在代码中,它不是字符串,但用示例字符串演示是最简单的。Tommorow我将在另一个ans中发布代码是的,但我会把你的作为被接受的。只为那些想知道同样事情的人。