Apesar de pouco comentado (pelo menos nos forums que eu participo participava), Boost é um conjunto de bibliotecas que facilitam muito a vida do programador e , sem dúvidas, é o plus-plus do C++. Se vc ainda não conhece: http://www.boost.org/.

Para quem não sabe, Boost.Asio é uma biblioteca multiplataforma (cross-platform) para programação de rede/comunicação (network) e operações de entrada e saída em baixo nível (low-level I/O) que oferece, aos desenvolvedores, um modelo consistente e assíncrono.

(Essa definição foi descaradamente traduzida da encontrada no site oficial)

Então, o que eu posso fazer com isso?

Você pode, por exemplo, usar sockets (TCP, UDP e ICMP), Timers e criar/manipular portas seriais.

Mas eu sei fazer isso! É só incluir o winsock.h e… no linux é fácil tb…

Não ter que se preocupar com o startup e cleanup do Winsock e não ter que colocar 8463763 #ifdef’s no meio do código já é um bom motivo para usar Boost.Asio. Se vc escrever “socket.read_some(…);“, vai funcionar em qualquer plataforma suportada (Win32/64, Linux kernel 2.4+, Solaris, Mac OS X 10.4+).

Beleza! Cadê os exemplos?

Antes disso, para não ficar perdido, é necessário entender como o Boost.Asio trabalha. Ao inves de oferecer um modelo genérico aproximado ao que há de comum entre as várias plataformas, a biblioteca apresenta uma nova proposta: para efetuar operações de entrada e saída seu programa precisa de, no mínimo, um objeto io_service (boost::asio::io_service). O objeto io_service funciona como um intermediário entre o seu software e o sistema operacional. Overhead? Tenha certeza que o boost faz esse intermédio da forma mais eficiente possível e, até hoje, nunca vi ninguém reclamando sobre o desempenho da biblioteca. A imagem abaixo (que foi retirada do site oficial) mostra o funcionamento do Boost.Asio para operações síncrona:

  1. O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);
  2. O objeto i/o encaminha a requisição de conexão para o objeto io_service;
  3. O objeto io_service faz uma chamada ao sistema operacional para realizar a conexão;
  4. O sistema operacional retorna um resultado para o objeto io_service;
  5. O objeto io_service “traduz” qualquer erro resultante na operação e retorna ao objeto i/o; e
  6. O objeto i/o retorna o resultado para o programa.

O modelo para operações assíncronas é representado pelo diagrama ao lado:

Ao invés de esperar cada etapa do modelo síncrono, aqui podemos passar uma função handler que será chamada assim que a operação for concluída, independente da ocorrência de erros.

As três primeiras etapas são praticamente idênticas ao modelo anterior (do ponto de vista do usuário/programador):

  1. O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);
  2. O objeto i/o encaminha a requisição de conexão para o objeto io_service; e
  3. O objeto io_service faz uma chamada ao sistema operacional para realizar a conexão;

Após as etapas indicadas, o sistema operacional indica o resultado da operação colocando-o em uma fila que será lida pelo objeto io_service, que por sua vez “traduz” qualquer mensagem de erro e chama a função handler passada como parâmetro pelo programa.

É importante comentar que, para que o objeto io_service possa tratar as tarefas/operações assíncronas pendentes, é necessário chamar io_service::run().

A função io_service::run() retornará assim que não houver mais tarefa assíncronas pendentes.

Okay! Então eu crio um objeto io_service e já era?

Aí é que está a grande maravilha do modelo proposto: usando vários objetos io_service (um em cada thread) e dividindo as operações entre eles, permitimos ao sistema operacional também dividí-las entre os vários núcleo disponíveis!

Tá… e os exemplos?

Timer

Para um wait síncrono (só retorna depois de completo):

#include <iostream>
#include <boost/asio.hpp>
 
using boost::asio::io_service;
using boost::asio::deadline_timer;
 
int main(int ac, char ** av)
{
    io_service ios;
    
    deadline_timer t(ios);
    t.expires_from_now(boost::posix_time::seconds(5));
    
    std::cout << "Esperando 5 segundos..." << std::endl;
    
    t.wait();
    
    std::cout << "Continua..." << std::endl;
    return 0;
}

Para um timer assíncrono, precisamos de um handler:

void handler(boost::system::error_code & ec)
{
    if(ec)
        //erro
    else
        //ok
}

Então, podemos usar o wait assíncrono:

t.expires_from_now(boost::posix_time::milliseconds(400));
t.async_wait(handler);
ios.run();

Um exemplo de timer assíncrono:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
 
using boost::asio::io_service;
using boost::asio::deadline_timer;
 
void handler(int segundo, boost::system::error_code & ec)
{
    if(!ec)
        std::cout << "Esperando... " << segundo << std::endl;
}
 
int main(int ac, char ** av)
{
    io_service ios;
 
    for(int i = 1; i <= 5; i++)
    {
        deadline_timer * t = new deadline_timer(ios);
        t->expires_from_now(boost::posix_time::seconds(i));
        t->async_wait(boost::bind(&handler, i, boost::asio::placeholders::error));
    }
 
    ios.run();
 
    std::cout << "Continua..." << std::endl;
    return 0;
}

Repare que não me preocupei em manter uma referência para os objetos criados dinamicamente (para apagá-los posteriormente), pois o programa é terminado logo após o retorno do último timer assíncrono.

Socket

Um exemplo simples de socket (tcp) que se conecta ao site:

#include <iostream>
#include <boost/asio.hpp>
 
using boost::asio::io_service;
using boost::asio::ip::tcp;
 
int main(int ac, char ** av)
{
    io_service ios;
    
    tcp::socket sck(ios);
    tcp::endpoint endp(boost::asio::ip::address::from_string("64.191.3.101"), 80);
    
    try
    {
        sck.connect(endp);
        std::cout << "Conectado!" << std::endl;
    }
    catch(boost::system::system_error & error)
    {
        std::cout << "Erro ao conectar: " << error.what() << std::endl;
    }
    
    std::cout << "Continua..." << std::endl;
    return 0;
}

Ou um resolver:

#include <iostream>
#include <boost/asio.hpp>
 
using boost::asio::io_service;
using boost::asio::ip::tcp;
 
int main(int ac, char ** av)
{
    io_service ios;
    
    tcp::resolver resolver(ios);
    tcp::resolver::query query("blog.delarco.com.br", "http");
    tcp::resolver::iterator iter = resolver.resolve(query);
    tcp::resolver::iterator end;
    
    while (iter != end)
    {
        tcp::endpoint endpoint = *iter++;
        std::cout << endpoint << std::endl;
    }
    
    return 0;
}