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:

- O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);
- O objeto i/o encaminha a requisição de conexão para o objeto io_service;
- O objeto io_service faz uma chamada ao sistema operacional para realizar a conexão;
- O sistema operacional retorna um resultado para o objeto io_service;
- O objeto io_service “traduz” qualquer erro resultante na operação e retorna ao objeto i/o; e
- 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):
- O programa inicia a conexão chamando o objeto i/o (socket, por exemplo);
- O objeto i/o encaminha a requisição de conexão para o objeto io_service; e
- 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;
}
Recent Comments