簡體   English   中英

Boost :: Beast:帶有websocket管道的服務器

[英]Boost::Beast : server with websocket pipelining

我正在編寫一個帶有boost野獸1.70和mysql 8 C連接器的c ++ websocket服務器。 服務器將同時連接多個客戶端。 特殊性是每個客戶端將連續執行100個websocket請求到服務器。 對於我的服務器,每個請求都是“cpu light”,但服務器為每個請求執行“時間繁重”的sql請求。

我已經使用websocket_server_coro.cpp示例啟動了我的服務器。 服務器步驟是:

1)websocket閱讀

2)一個sql請求

3)websocket寫

問題是對於給定用戶,服務器在步驟2被“鎖定”,並且在該步驟和步驟3結束之前無法讀取。 因此,順序地解決了100個請求。 這對我的用例來說太慢了。

我已經讀過使用boost野獸無法進行非阻塞讀/寫操作。 但是,我現在要做的是在協程中執行async_read和async_write。

void ServerCoro::accept(websocket::stream<beast::tcp_stream> &ws) {
    beast::error_code ec;

    ws.set_option(websocket::stream_base::timeout::suggested(beast::role_type::server));

    ws.set_option(websocket::stream_base::decorator([](websocket::response_type &res) {
                res.set(http::field::server, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-Server-coro");
            }));

    ws.async_accept(yield[ec]);
    if (ec) return fail(ec, "accept");

    while (!_bStop) {
        beast::flat_buffer buffer;
        ws.async_read(buffer, yield[ec]);

        if (ec == websocket::error::closed) {
            std::cout << "=> get closed" << std::endl;
            return;
        }

        if (ec) return fail(ec, "read");

        auto buffer_str = new std::string(boost::beast::buffers_to_string(buffer.cdata()));
        net::post([&, buffer_str] {

            // sql async request such as :
            // while (status == (mysql_real_query_nonblocking(this->con, sqlRequest.c_str(), sqlRequest.size()))) {
            //    ioc.poll_one(ec);
            // }
            // more sql ...

            ws.async_write(net::buffer(worker->getResponse()), yield[ec]); // this line is throwing void boost::coroutines::detail::pull_coroutine_impl<void>::pull(): Assertion `! is_running()' failed.
            if (ec) return fail(ec, "write");

        });
    }
}

問題是帶有async_write的行會拋出一個錯誤:

void boost :: coroutines :: detail :: pull_coroutine_impl :: pull():斷言`! is_running()'失敗了。

如果用sync_write替換此行,它可以工作,但服務器對於給定用戶保持順序。 我試圖在單線程服務器上執行此代碼。 我也試過為async_read和async_write使用相同的鏈。 仍然有斷言錯誤。

對於websocket來說,這樣的服務器是不可能的? 謝謝。

按照Vinnie Falco的建議,我使用“websocket chat”和“async server”作為例子來重寫代碼。 以下是代碼的最終工作結果:

void Session::on_read(beast::error_code ec, std::size_t bytes_transferred)
{
    boost::ignore_unused(bytes_transferred);

    if(ec == websocket::error::closed) return;  // This indicates that the Session was closed
    if(ec) return fail(ec, "read");

    net::post([&, that = shared_from_this(), ss = std::make_shared<std::string const>(std::move(boost::beast::buffers_to_string(_buffer.cdata())))] {
        /* Sql things that call ioc.poll_one(ec) HERE, for me the sql response go inside worker.getResponse() used below */

        net::dispatch(_wsStrand, [&, that = shared_from_this(), sss = std::make_shared < std::string const>(worker.getResponse())] {
            async_write(sss);
        });
    });
    _buffer.consume(_buffer.size()); // we remove from the buffer what we just read
    do_read(); // go for another read
}

void Session::async_write(const std::shared_ptr<std::string const> &message) {
    _writeMessages.push_back(message);

    if (_writeMessages.size() > 1) {
        BOOST_LOG_TRIVIAL(warning) << "WRITE IS LOCKED";
    } else {
        _ws.text(_ws.got_text());
            _ws.async_write(net::buffer(*_writeMessages.front()), boost::asio::bind_executor(_wsStrand, beast::bind_front_handler(
                    &Session::on_write, this)));
    }
}

void Session::on_write(beast::error_code ec, std::size_t)
{
    // Handle the error, if any
    if(ec) return fail(ec, "write");

    // Remove the string from the queue
    _writeMessages.erase(_writeMessages.begin());

    // Send the next message if any
    if(!_writeMessages.empty())
        _ws.async_write(net::buffer(*_writeMessages.front()), boost::asio::bind_executor(_wsStrand, beast::bind_front_handler(
                        &Session::on_write, this)));
}

謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM