Exceção

O Asio fornece duas formas de lidar com erros nas operações de rede: por exceção (comportamento padrão) e por código de erro (sem exceção, usando error_code). Conhecer as duas formas é fundamental para escrever código robusto.

Tratamento por Exceção

Por padrão, as funções síncronas do Asio lançam asio::system_error (standalone) ou boost::system::system_error (Boost.Asio) quando ocorre um erro. Ambas derivam de std::runtime_error.

O Asio fornece uma série de exceções de erro que incluem:

  • asio::error::address_family_not_supported: o tipo de endereço especificado não é suportado pela plataforma.
  • asio::error::address_in_use: o endereço especificado já está em uso por outro processo.
  • asio::error::connection_aborted: a conexão foi abortada pelo host remoto.
  • asio::error::connection_refused: a conexão foi recusada pelo host remoto.
  • asio::error::connection_reset: a conexão foi reiniciada pelo host remoto.
  • asio::error::eof: o par encerrou a conexão (fim de arquivo/stream).
  • asio::error::timed_out: a operação excedeu o tempo limite.
  • asio::error::host_not_found: o nome do host não pôde ser resolvido.

Essas exceções são lançadas pelos métodos do Asio que realizam operações de rede síncronas e podem ser capturadas e tratadas de acordo com o erro específico:

#include <asio.hpp>
#include <iostream>

int main()
{
    try {
        asio::io_context io_context;
        asio::ip::tcp::resolver resolver{io_context};

        // Lança asio::system_error se a resolução falhar
        auto endpoints = resolver.resolve("host.invalido.exemplo", "https");

        for (const auto& ep : endpoints)
            std::cout << ep.endpoint() << '\n';

    } catch (const asio::system_error& e) {
        // e.code() retorna o error_code específico
        std::cerr << "Erro Asio [" << e.code() << "]: " << e.what() << '\n';
    } catch (const std::exception& e) {
        std::cerr << "Exceção: " << e.what() << '\n';
    }

    return 0;
}

A função membro what() retorna as informações detalhadas da exceção, enquanto code() retorna o error_code correspondente.

Tratamento por Código de Erro (sem exceção)

A maioria das funções síncronas do Asio possui uma sobrecarga que recebe um asio::error_code por referência. Nesse caso, nenhuma exceção é lançada — o erro é armazenado no error_code e a função retorna normalmente:

#include <asio.hpp>
#include <iostream>

int main()
{
    asio::io_context io_context;
    asio::ip::tcp::socket socket{io_context};

    asio::ip::tcp::endpoint endpoint{
        asio::ip::make_address("192.168.1.1"), 8080};

    // Sobrecarga sem exceção: erro armazenado em 'ec'
    asio::error_code ec;
    socket.connect(endpoint, ec);

    if (ec) {
        if (ec == asio::error::connection_refused)
            std::cerr << "Conexão recusada!\n";
        else
            std::cerr << "Erro ao conectar: " << ec.message() << '\n';
        return 1;
    }

    std::cout << "Conectado com sucesso!\n";
    return 0;
}

Verificando erros em operações assíncronas

Nos callbacks de operações assíncronas, o primeiro parâmetro é sempre um error_code:

socket.async_receive(asio::buffer(buffer),
    [](const asio::error_code& ec, std::size_t bytes) {
        if (ec) {
            if (ec == asio::error::eof) {
                std::cout << "Conexão encerrada pelo par\n";
            } else {
                std::cerr << "Erro: " << ec.message() << '\n';
            }
            return;
        }
        // Processar bytes recebidos...
        std::cout << "Recebidos " << bytes << " bytes\n";
    });

Tabela de Erros Comuns

Código de ErroSignificadoCausa Comum
asio::error::eofFim da conexãoPar encerrou a conexão normalmente
asio::error::connection_refusedConexão recusadaPorta fechada no servidor
asio::error::connection_resetConexão reiniciadaDesconexão abrupta
asio::error::connection_abortedConexão abortadaTimeout ou erro de rede
asio::error::address_in_useEndereço em usoPorta já ocupada
asio::error::host_not_foundHost não encontradoFalha de DNS
asio::error::timed_outTempo esgotadoServidor não respondeu
asio::error::operation_abortedOperação canceladacancel() ou stop() chamado

Standalone vs Boost.Asio

AspectoStandalone AsioBoost.Asio
Tipo de erroasio::error_codeboost::system::error_code
Exceçãoasio::system_errorboost::system::system_error
Categoriaasio::error::get_system_category()boost::system::system_category()

Dica: Em código de produção, prefira a sobrecarga com error_code para operações críticas, pois o tratamento explícito de erros é mais eficiente e previsível do que o mecanismo de exceções.