【问题标题】:boost asio tcp async read/writeboost asio tcp 异步读/写
【发布时间】:2015-06-30 08:48:10
【问题描述】:

我对 boost asio 如何处理这个问题有一个理解:

当我在客户端查看我的请求响应时,我可以使用以下 boost 示例 Example

但我不明白如果服务器每 X 毫秒向客户端发送一些状态信息会发生什么。我是否为此打开了一个单独的套接字,或者我的客户差异是请求、响应和 cycleMessage 吗?

客户端发送请求并读取为循环消息是否会发生?因为他也在等待 async_read 因为这个 Message?


class TcpConnectionServer : public boost::enable_shared_from_this<TcpConnectionServer>
{
public:
    typedef  boost::shared_ptr<TcpConnectionServer> pointer;
    static pointer create(boost::asio::io_service& io_service)
    {
        return pointer(new TcpConnectionServer(io_service));
    }
    boost::asio::ip::tcp::socket& socket()
    {
        return m_socket;
    }
    void Start()
    {
        SendCycleMessage();
        boost::asio::async_read(
                m_socket, boost::asio::buffer(m_data, m_dataSize),
                boost::bind(&TcpConnectionServer::handle_read_data, shared_from_this(), boost::asio::placeholders::error));
    }

private:
    TcpConnectionServer(boost::asio::io_service& io_service)
        : m_socket(io_service),m_cycleUpdateRate(io_service,boost::posix_time::seconds(1))
      {

      }
    void handle_read_data(const boost::system::error_code& error_code)
    {
        if (!error_code)
        {
        std::string answer=doSomeThingWithData(m_data);
        writeImpl(answer);

        boost::asio::async_read(
                m_socket, boost::asio::buffer(m_data, m_dataSize),
                boost::bind(&TcpConnectionServer::handle_read_data, shared_from_this(), boost::asio::placeholders::error));
        }
        else
        {

            std::cout << error_code.message() << "ERROR DELETE READ \n";
            // delete this;
        }
    }


    void SendCycleMessage()
    {
        std::string data = "some usefull data";
        writeImpl(data);
        m_cycleUpdateRate.expires_from_now(boost::posix_time::seconds(1));
        m_cycleUpdateRate.async_wait(boost::bind(&TcpConnectionServer::SendTracedParameter,this));
    }

    void writeImpl(const std::string& message)
    {
        m_messageOutputQueue.push_back(message);
        if (m_messageOutputQueue.size() > 1)
        {
            // outstanding async_write
            return;
        }

        this->write();
    }

    void write()
    {
        m_message = m_messageOutputQueue[0];
        boost::asio::async_write(
                m_socket,
                boost::asio::buffer(m_message),
                boost::bind(&TcpConnectionServer::writeHandler, this, boost::asio::placeholders::error,
                            boost::asio::placeholders::bytes_transferred));
    }

    void writeHandler(const boost::system::error_code& error, const size_t bytesTransferred)
    {
        m_messageOutputQueue.pop_front();
        if (error)
        {
            std::cerr << "could not write: " << boost::system::system_error(error).what() << std::endl;
            return;
        }

        if (!m_messageOutputQueue.empty())
        {
            // more messages to send
            this->write();
        }
    }

    boost::asio::ip::tcp::socket m_socket;
    boost::asio::deadline_timer m_cycleUpdateRate;
    std::string m_message;

    const size_t m_sizeOfHeader = 5;
    boost::array<char, 5> m_headerData;
    std::vector<char> m_bodyData;

    std::deque<std::string> m_messageOutputQueue;
};

有了这个实现,我将不需要 boost::asio::strand 还是?因为我不会从其他线程修改 m_messageOutputQueue。

但是当我在客户端有一个 m_messageOutputQueue 时,我可以从其他线程访问它,此时我需要 strand 吗?因为那我需要同步?我是不是理解错了?

【问题讨论】:

  • 你指的cycleMessage是什么?
  • cycleMessage是从服务器到客户端的消息。它可以用于例如时间戳,每 X 毫秒发送一次

标签: c++ boost tcp boost-asio


【解决方案1】:

消息的区分是您的应用程序协议的一部分。

ASIO 仅提供传输。

现在,确实,如果您想要一个“keepalive”消息,您将必须设计您的协议,以便客户端可以区分这些消息。

诀窍是在更高的层次上考虑它。不要直接在客户端处理async_read。相反,让async_read 将消息放在一个队列(或多个队列;状态消息甚至不能进入队列但取代先前未处理的状态更新,例如)。

然后针对这些队列编写您的客户端代码。

通常要做的一个简单的事情是引入消息框架和消息类型 id:

FRAME offset 0: message length(N)
FRAME offset 4: message data
FRAME offset 4+N: message checksum
FRAME offset 4+N+sizeof checksum: sentinel (e.g. 0x00, or a larger unique signature)

那里的结构使协议更具可扩展性。无需接触所有其他代码即可轻松添加加密/压缩。有内置的错误检测等。

【讨论】:

  • 感谢您的回答。一个我不清楚的问题:我的客户不可能将 async_write 作为请求并且客户 async_read 得到它吗?是否总是只保存客户端的服务器读写?如果我的客户端和服务器同时写入会发生什么?
  • 不,这不会发生。流套接字是全双工通道。您在一端写的内容(仅)在另一端输出
  • 客户端和服务器无论如何都有不同的套接字(假设你实际上并没有在同一个进程中编写它们......)。在同一个进程中,您需要在单个套接字上同步操作。
  • 我假设在 io_service.run() 的一个实例中我不必同步或者?我在客户端尝试了一个 async_read,它一直在读取我的套接字,并且我有一个 sendMessage 方法,当我收到用户输入时,它会将数据写入套接字。我认为 boost asio 可以进行同步?
  • “内部运行()”是什么意思?那是图书馆内部。如果您的意思是“只有一个线程运行io_service::run(),那么,是的,您拥有所谓的an implicit strand。另见stackoverflow.com/questions/12794107/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多