jobzzoff
@jobzzoff
I wonder how, I wonder why...

Блокирующий вызов io_context.run() и socket.connect(). Как исправить?

При вводе некорректного ip-адреса или номера порта, модуль кода, использующий boost::asio уходит в блок перманентно.
Простой пример кода:
int main(int argc, char* argv[]){

namespace ba = boost::asio;
using ba::ip::tcp;

ba::io_service service;
tcp::socket s(service);

if (argc<3)
    return 255;

try {
    auto it = tcp::resolver(service).resolve({argv[1], argv[2]});
   
 s.connect(*it); // first resolved value


    std::cout << "Connected " << s.local_endpoint() << " -> " << s.remote_endpoint() << "\n";

    // demo write
    ba::write(s, ba::buffer("hello world\n"));
} catch (const boost::system::system_error& e) {
    std::cout << "ERROR:" << e.what() << "\n";
}}

Проблем не возникает, если заранее известно, что по адресу, который мы подали в программу, находится валидный и вполне себе жизнеспособный хост. К примеру, если ввести "127.0.0.1" или "192.168.10.17"(адрес одной из домашних машин) то программа отработает корректно и выведет заветное "Connected". Однако если ввести адрес вроде "1.2.3.4" или "12.13.14.15", "107.210.211.97" то на моменте

s.connect(*it); // first resolved value

Весь поток выполнения блокируется. Перманентно. Завершить программу можно только с помощью ручного завершения процесса.

Более комплексный пример:

boost::asio::io_context io_context;
    boost::asio::ip::tcp::resolver resolver(io_context);
    boost::asio::ip::tcp::resolver::results_type endpoints;


    std::string address = ui->lineEdit_primaryServerAddress->text().toStdString();
    endpoints = resolver.resolve(address, INET_SERVICE);

    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
    ctx.load_verify_file(SSL_CERT);

    rb_baseClient c(io_context, ctx, endpoints);
    c.set_request(CLNT_MSG_WHO_ARE_YOU);

    try
    {
        boost::system::error_code _ec2;
        io_context.run();
    }

    catch (std::exception& e)
    {
        io_context.stop();
        std::cerr << e.what() << std::endl;
        ui->label_primaryServerHostname->setStyleSheet("color: darkred");
        this->pServerIsAlive = false;
        emit pServerStatusChanged(false);
    }

    std::string reply=c.get_reply();

Это часть кода для клиента одного из проектов. Программа должна подсоединится по полученному из gui адресу к хосту, проверить валидность по, установленного на том конце, и в зависимости от реплая определить дальнейшие элементы граф. интерфейса. Если адрес корректный, то все работает так, как задумано. Однако если ввести некорректный адрес, к примеру, тот же "1.2.3.4" или десятичное число, к примеру, "1" или "15212", то поток выполнения уходит в блокирующий режим на моменте

io_context.run();

Отдебажить io_context.run(); не предоставляется возможным.
IO context наполняется в классе клиента. Вот его вырезка:

rb_baseClient::rb_baseClient(boost::asio::io_context& io_context, boost::asio::ssl::context& context,
                             boost::asio::ip::tcp::resolver::results_type endpoints) :
    _socket(io_context, context), _endpoints(endpoints)
{
    //    memset(_reply, 0, max_length);
    //    memset(_request, 0, max_length);
    this->connect();
}


void rb_baseClient::connect()
{
try
{
    _socket.set_verify_mode(boost::asio::ssl::verify_peer);
    _socket.set_verify_callback(
                boost::bind(&rb_baseClient::verify_certificate, this, _1, _2));

    boost::asio::async_connect(_socket.lowest_layer(), _endpoints,
                               boost::bind(&rb_baseClient::handle_connect, this,
                                           boost::asio::placeholders::error));
}
catch (std::exception& e)
{
    cerr << "rb_baseClient::connect: " << e.what();
    strcpy(_reply, SERVER_CONNECTION_FAILED);
}
}

Обращался к официальной документации boost, но не смог найти там решение этой проблемы. Пытался также добавлять deadline-timers - но это оказалось бесполезным. Google и Yandex не помогли тоже.
  • Вопрос задан
  • 600 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы