Работа с Boost.asio в Qt

Рейтинг: 0Ответов: 1Опубликовано: 20.05.2023

Изучаю Qt и Boost, столкнулся со следующей проблемой: При запуске io_context не появляется интерфейс приложения. Содержимое файла main.cpp:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    boost::asio::io_context io_context;
    boost::asio::ip::tcp::resolver resolver(io_context);
    auto endpoints = resolver.resolve("127.0.0.1", "8080");
    Session::setInstance(io_context, endpoints);
    io_context.run();

    MainWindow w;
    w.show();
    AuthWindow authWindow(&w, &w);
    authWindow.setModal(true);
    authWindow.exec();

    return a.exec();
}

Класс Session:

class Session {
public:
    Session(boost::asio::io_context& io_context, const tcp::resolver::results_type& endpoints)
            : io_context_(io_context), socket_(io_context) 
    {
        Connect(endpoint);
    }

    void Send(const std::string& msg) {
            auto parts = Split(str, Request::max_body_length);
        for (const auto& part : parts) {
            Request msg(part);
            boost::asio::post(io_context_, [this, msg]() {
                bool write_in_progress = !queue_.empty();
                queue_.push_back(msg);
                if (!write_in_progress) {
                    Write();
                }
            });
        }
    }

    void Close() {
        boost::asio::post(io_context_, [this]() { socket_.close(); });
    }
    
    static std::shared_ptr<Session> getInstance() {
        return session_instance_;
    }

    static void setInstance(boost::asio::io_context& io_context, const tcp::resolver::results_type& endpoints) {
         session_instance_ = std::make_shared<Session>(io_context, endpoint);
    }

private:

    inline static std::shared_ptr<Session> session_instance_ = nullptr;
    void Connect(const tcp::resolver::results_type& endpoint) {
            std::cout << "Connection" << std::endl;

    boost::asio::async_connect(
            socket_, endpoint, [this](boost::system::error_code ec, tcp::endpoint) {
                if (!ec) {
                    ReadHeader();
                } else {
                    std::cerr << ec.message() << std::endl;
                }
            });
    }

    void ReadHeader() {
            boost::asio::async_read(
            socket_,
            boost::asio::buffer(read_msg_.data(), Request::header_length),
            [this](boost::system::error_code ec, std::size_t length) {
                if (!ec && read_msg_.decode_header()) {
                    ReadBody();
                } else {
                    socket_.close();
                }
            });
    }

    void ReadBody() {
            boost::asio::async_read(
            socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
            [this](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    std::string body(read_msg_.body());
                    std::string response = body.substr(0, length);
                    std::cout << response << std::endl;
                    //////////PARSE//////////////
                    ReadHeader();
                } else {
                    std::cerr << ec.message() << std::endl;
                    socket_.close();
                }
            });
    }
    
    void Write() {
            boost::asio::async_write(
            socket_,
            boost::asio::buffer(queue_.front().data(),
                                queue_.front().length()),
            [this](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    queue_.pop_front();
                    if (!queue_.empty()) {
                        Write();
                    }
                } else {
                    std::cerr << ec.message() << std::endl;
                    socket_.close();
                }
            });
    }

    boost::asio::io_context& io_context_;
    tcp::socket socket_;
    Request read_msg_;
    std::list<Request> queue_;
};

Пробовал запускать io_context в потоке std::thread, но результат тот же.
Также пробовал запускать io_context при необходимости (когда отсылаем запрос, либо ждем ответ) и останавливать, когда никаких сетевых взаимодействий не ожидается. Но в таком случае приложение перестает воспринимать какие-либо действия, будь то ввод, или нажатие на кнопку.

Подскажите, пожалуйста, есть ли какой-то вариант "заставить" работать вместе Qt и Boost.asio? Или же будет необходимо использовать QtNetwork?

Ответы

▲ 0

Прочитал, что Qt работает в одном потоке. Судя по всему, из-за запуска io_context этот поток блокируется и ничего не происходит. Поэтому необходимо обернуть все сетевое взаимодействие в отдельный поток.

Решило проблему сделать так:

std::thread t([&io_context]() {
        io_context.run();
    });

Изначально у меня так не сработало из-за того, что я также написал t.join()