boost :: beast websocket异步读写连接丢失

时间:2018-08-14 18:28:08

标签: c++ boost websocket boost-beast

我正在尝试使用boost :: beast阅读RocketChat Websocket API。当我使用同步示例阅读它时,它可以工作,但是当使用async_ *函数时,它似乎以某种方式关闭了连接。

有问题的代码:

#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <iostream>
#include <deque>


class connection
{
    public:
        connection(boost::asio::io_context &io_context, boost::asio::ssl::context &ssl_context) :
            _io_context{ io_context },
            _resolver{ io_context },
            _websocket{ io_context, ssl_context },
            _dynamic_buffer{ boost::asio::dynamic_buffer(_read_buffer) }
        {}

        void connect(std::string_view host)
        {
            auto addresses = _resolver.resolve(host, "https");

            boost::asio::connect(_websocket.lowest_layer(), addresses);
            _websocket.next_layer().handshake(boost::asio::ssl::stream_base::client);
            _websocket.handshake(boost::beast::string_view{ host.data(), host.size() }, "/websocket");

            read_message();
        }

        void send(std::string &&message)
        {
            _write_buffer.push_back(std::move(message));

            if (_write_buffer.size() == 1) {
                send_message();
            }

            _websocket.write(boost::asio::buffer(message));
        }
    private:
        using tcp_socket = boost::asio::ip::tcp::socket;
        using ssl_socket = boost::asio::ssl::stream<tcp_socket>;

        void read_message()
        {
            _websocket.async_read(_dynamic_buffer, [this](const boost::system::error_code &error, size_t transferred) {
                if (error == boost::asio::error::operation_aborted) {
                    std::cout << "read aborted" << std::endl;
                    return;
                } else if (error) {
                    std::cout << "read error: " << error.message() << std::endl;
                    return;
                }

                std::cout << " >> " << _read_buffer << std::endl;

                _read_buffer.clear();
                read_message();
            });
        }

        void send_message()
        {
            if (_write_buffer.empty()) {
                return;
            }

            _websocket.async_write(boost::asio::buffer(_write_buffer.front()), [this](const boost::system::error_code &error, size_t transferred) {
                if (error == boost::asio::error::operation_aborted) {
                    std::cout << "write aborted" << std::endl;
                    return;
                } else if (error) {
                    std::cout << "write error: " << error.message() << std::endl;
                    return;
                }

                if (transferred != _write_buffer.front().size()) {
                    std::cout << "Wrote " << transferred << " bytes instead of the expected " << _write_buffer.front().size() << std::endl;
                    return;
                }

                std::cout << " << " << _write_buffer.front() << std::endl;

                _write_buffer.pop_front();
                send_message();
            });
        }

        boost::asio::io_context                             &_io_context;
        boost::asio::ip::tcp::resolver                      _resolver;
        boost::beast::websocket::stream<ssl_socket>         _websocket;
        std::string                                         _read_buffer;
        decltype(boost::asio::dynamic_buffer(_read_buffer)) _dynamic_buffer;
        std::deque<std::string>                             _write_buffer;
};

int main()
{
    boost::asio::io_context     io_context;
    boost::asio::ssl::context   ssl_context { boost::asio::ssl::context::sslv23_client  };
    connection                  connection  { io_context, ssl_context                   };

    connection.connect("open.rocket.chat");
    send("{\"msg\":\"connect\",\"version\":\"1\",\"support\":[\"1\"]}");
    io_context.run();
}

运行此代码将产生以下输出:

 >> {"server_id":"0"}
 << {"msg":"connect","version":"1","support":["1"]}
read error: The WebSocket stream was gracefully closed at both endpoints

如果我在连接后没有发送初始消息,则连接不会关闭。如果我不是使用异步版本,而是使用同步版本,那么它也不会关闭。

我做错了可能很愚蠢。如果我正确解释了文档,则只要在同一套接字上完成对websocket的读写操作,就应该是有效的,并且由于我只有一个线程,因此我应该有一个隐式线程。

我在做什么错了?

0 个答案:

没有答案