【问题标题】:Having a hard time understanding a few concepts with Boost ASIO TCP with async_read and async_write使用 async_read 和 async_write 的 Boost ASIO TCP 很难理解一些概念
【发布时间】:2012-11-09 18:54:58
【问题描述】:

在使用 async_read 和 async_write 时,我很难理解构建 tcp 客户端的正确方法。 examples 似乎在连接后执行 async_read ,然后在处理程序中有 async_write 。

对于我的客户端和服务器,当客户端连接时,它需要检查要写入的消息队列并检查是否需要读取任何内容。我遇到困难的一件事是理解这将如何异步工作。

我的设想是在 async_connect 处理程序中,如果 sendQueue 中有任何内容,线程将调用 async_write 并一遍又一遍地调用 async_read。还是应该在执行 async_read 之前检查是否有任何内容可供读取? 下面是我所说的一个例子。

void BoostTCPConnection::connectHandler()
{
    setRunning(true);
    while (isRunning())
    {
        //If send Queue has messages
        if ( sendSize > 0)
        {
            //Calls to async_write
            send();
        }

        boost::shared_ptr<std::vector<char> > sizeBuffer(new std::vector<char>(4));
        boost::asio::async_read(socket_, boost::asio::buffer(data, size), boost::bind(&BoostTCPConnection::handleReceive, shared_from_this(), boost::asio::placeholders::error, sizeBuffer));

   }    
}

void BoostTCPConnection::handleReceive(const boost::system::error_code& error, boost::shared_ptr<std::vector<char> > sizeBuffer)
{

    if (error)
    {
        //Handle Error
        return;
    }

    size_t messageSize(0);
    memcpy((void*)(&messageSize),(void*)sizeBuffer.data(),4);

    boost::shared_ptr<std::vector<char> > message(new std::vector<char>(messageSize) );

    //Will this create a race condition with other reads?
    //Should a regular read happen here
    boost::asio::async_read(socket_, boost::asio::buffer(data, size), 
                    boost::bind(&BoostTCPConnection::handleReceiveMessage, shared_from_this(),
                    boost::asio::placeholders::error, message));

}

void BoostTCPConnection::handleReceiveMessage(const boost::system::error_code& error, boost::shared_ptr<std::vector<char> > rcvBuffer)
{
    if (error)
    {
        //Handle Error
        return;
    }

    boost::shared_ptr<std::string> message(new std::string(rcvBuffer.begin(),rcvBuffer.end())); 
    receivedMsgs_.push_back(message);
}

void BoostTCPConnection::handleWrite(const boost::system::error_code& error,size_t bytes_transferred)
{
    //Success
    if (error.value() == 0) 
        return;
    //else handleError


}

【问题讨论】:

    标签: c++ networking boost tcp boost-asio


    【解决方案1】:

    从概念上讲,async_read 等待接收数据。每当您希望在收到数据并且读取尚未挂起时发生某些事情时,您都应该调用它。同样,async_write 等待数据写入。您应该在需要写入数据且写入尚未挂起的任何时候调用它。

    您应该在完成连接后致电async_read。在您的async_read 处理程序返回之前,它可能应该再次调用async_read

    当您需要写入连接时,您应该调用async_write(如果写入尚未挂起)。在你的async_write处理程序中,如果你还需要写更多,你应该再次调用async_write

    如果没有读取已挂起,您可以在写入处理程序中调用async_read,如果您希望在完成写入后继续读取。您也可以只保持读取始终未决。这取决于你。

    在致电async_read 之前,您不应检查是否有任何内容要阅读。 async_read 的重点是在有内容要阅读时完成。在此期间等待和做其他事情是一种聪明的方式。

    【讨论】:

    • 嗯,阅读很容易。完成连接后调用async_read,然后在读取处理程序返回之前再次调用它。写有点复杂,但你可以在有两种情况时调用它:1)你有你想要写的数据。 2) 您没有等待异步写入。
    • 如果您有数据要发送,请致电async_send,除非发送已挂起。在您的发送处理程序中,再次调用async_send,除非您没有任何东西要发送。如果您有自己的发送队列,您可以创建一个“将消息放入发送队列”功能,为您完成所有这些工作。
    • @ThomasLann:对于异步编程,将函数视为链接在一起而不是循环可能会有所帮助。 This 回答展示了如何实现一个基本的写入队列,用一个链维护线程安全,以及有条件地启动一个异步写入调用链。基本模式保持不变,即使对于要求稍微复杂一些的解决方案,例如不复制写入缓冲区并传播处理程序回调的解决方案。
    • @ThomasLann:您不需要检查发送队列的循环。如果写入尚未挂起,您需要一个将某些内容放入发送队列并调用async_write 的函数。
    • @ThomasLann 它如何导致任何消息被延迟?您始终处于以下两种状态之一:1)您有一个空的发送队列。 2)你有一个写挂起。 -- 任何时候你将一条消息放在一个空的发送队列中并且写入没有挂起,你调用async_send
    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多