提升asio tcp异步读/写

时间:2015-06-30 08:48:11

标签: c++ boost tcp boost-asio

我有一个理解问题,如何提升asio处理这个问题:

enter image description here

当我在客户端观看请求响应时,我可以使用以下提升示例Example

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

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

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,我可以从这一点上的另一个线程访问我需要链?因为那时我需要同步?我理解错了吗?

1 个答案:

答案 0 :(得分:2)

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

ASIO仅提供运输。

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

诀窍是在更高的层次上考虑它。不要直接在客户端上处理async_read。相反,make 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)

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