domingo, 20 de março de 2016

Hardcore Devel #56 - Sockets: BSD para Windows

Se você desenvolveu uma aplicação que utiliza rede em um ambiente Unix, é bem provável que você já saiba o que é um Socket BSD.


Não, um socket BSD não tem nada a ver com o FreeBSD. Mantenha a calma.

O que acontece é que a Universidade de Berkeley sempre esteve participando ativamente do desenvolvimento de software, seja ele de código aberto ou de código fechado. Os sockets implementados em baixo nível por essa galera acabou sendo aproveitado também para as distribuições Linux e são o padrão dos sistemas operacionais.

Mas a Microsoft não gosta de padrões. Se você vai programar usando Sockets, você tem que usar Winsock, que ja é um nome feio por sinal porque parece que você está falando de meias, e não mais de soquetes. Felizmente o nosso querido Bill Gates teve um pouco de bom senso e tentou fazer tudo o mais parecido o possível com a interface criada pelo BSD.

Isso significa utilizar os mesmos nomes e mesma quantidade de parâmetros para funções. Isso significa que o seu código é quase que completamente portável bastante o uso dos includes corretos, porém, como tudo no Windows, tem os seus detalhes sórdidos necessários para fazer a coisa funcionar.

Então vamos lá! Vamos aprender a fazer o port da sua aplicação Unix pra uma aplicação Microsoft. nesse caso você pode até usar o MinGW que tudo funciona maravilhosamente bem, aliás acho que a Toolchain do MinGW é a melhor pra fazer portabilidade Unix para Windows.

A primeira magia está em você adicionar a seguinte linha de código logo depois dos includes, uma vez que é um comando de pré-processamento. Você vai adicionar isso nos arquivos que vão de fato utilizar as funções de Socket como recv e sendto.

#pragma comment(lib, "Ws2_32.lib")

O que eu faço geralmente é criar uma camada de abstração que implemente os Sockets, então basta eu alterar um arquivo que faz as chamadas aos sockets.

Obviamente ao invés de você incluir as bibliotecas do Unix como a sys/socket.h, você vai incluir a nossa querida Winsock2.h. É uma linha de include importante a ser destacada.

#include<winsock2.h>

Cara, estamos quase lá, mas para que a coisa toda funciona, antes da sua aplicação começar, você vai precisar ver se ela vai conseguir utilizar os sockets, e essa é uma das linhas de códigos que devem ir na sua função principal antes dos outros componentes do eu programa começarem a funcionar:

int status;
WSADATA wsadata;

status = WSAStartup(MAKEWORD(2,2), &wsadata);
if(status != 0)
{
cout << "windows stuff problems" << endl;
return 4;
}

Ok, se você olhar essa linha de codigo você vai entender o seguinte: WSAStartup é uma função que recebe dois argumentos e retorna algum valor para status. MAKEWORD é uma função do windows que eu não faço idéia do que faz, mas eu sei que se o valor de status for diferente de 0 é porque a função deu algum xabu, então é melhor eu abortar a execução.

Isso deve ser o suficiente para a maioria dos casos mas não é tudo! Algumas funções importantes como setsockopt também funcionam com leves diferenças. Veja:

DWORD time;

time = 1000;
len = sizeof(DWORD);
setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, (char*)&time, len);

esse é um exemplo onde alteramos o timeout para 1 segundo. Muitas vezes você vai precisar passar parâmetros do tipo DWORD e aí não tem jeito, você vai precisar consultar a referência da Microsoft, que para nossa felicidade é uma referência aberta. A gente te oferece um atalho gratuitamente.

É basicamente isso que você precisa pra fazer a sua aplicação com sockets BSD funcionar no Windows. Você encontra isso tudo na referência da Microsoft.

Mas por aqui é bem mais rápido, né? =P

Nenhum comentário:

Postar um comentário