Tuesday, October 20, 2015

Códigos Unsafe e Ponteiros no .NET C#

Código Unsafe e Ponteiros no .NET Framework com C#

Neste artigo, aprenderemos a tratar diretamente a memória do computador, com o uso de ponteiros na plataforma .NET 2.0 com a linguagem C#


O .NET Framework possui um excelente gerenciamento de memória através da Garbage Collector em conjunto com os tipos por referência, mas nós podemos ter acesso direto a memória através dos ponteiros.
Veremos neste artigo como manipular ponteiros no .NET Framework 2.0 com C#.

1 - A Palavra Chave unsafe

A palavra chave unsafe delimita um contexto onde podemos escrever códigos que envolvam a manipulação de ponteiros. Pode ser utilizada na declaração de um membro ou um tipo e não pode ser utilizada em uma variável local, entretanto, podemos marcar um trecho de um método como unsafe.
A seguir, veremos alguns exemplos de onde podemos utilizar a palavra chave unsafe.

A) Declaração de uma classe como unsafe:

public unsafe class Classe { }

B) Declaração de membros da classe como unsafe:

private unsafe int *_valor; public unsafe void Incrementar() { }

C) Declaração unsafe no corpo de um método:

public void Incrementar() { unsafe { } }


Para que um código que seja declarado com o modificador unsafe possa ser compilado no Framework 2.0, precisamos informar isso ao compilador.
Quando a compilação é realizada através de linha de comando, informamos o compilador incluindo /unsafe, na Figura 1.1 podemos ver a estrutura do comando de compilação.

 
Figura 1: Compilando a aplicação. 

Com o Visual Studio 2005, precisamos marcar a opção "Allow unsafe code", nas propriedades do projeto.

 
Figura 2: Propriedades do projeto. 

Neste momento, nossa aplicação está apta a trabalhar com ponteiros.

2 - Ponteiros
Um ponteiro pode ser definido como uma variável que contém um endereço de memória.
Os ponteiros são considerados uma das ferramentas mais poderosas para quem desenvolve aplicações utilizando linguagens como C e C++.
No .NET Framework, podemos criar ponteiros dos seguintes tipos:
  • byte;
  • sbyte;
  • ushort;
  • short;
  • uint;
  • int;
  • ulong;
  • long;
  • float;
  • double;
  • decimal;
  • char;
  • bool;
  • enum;
  • struct (Ponteiros de estruturas só podem ser utilizados caso a estrutura possua apenas campos com os tipos que citamos anteriormente)
  • void(Ponteiro para um tipo indefinido)
Vejamos agora alguns exemplos

1º Exemplo:

static unsafe void Main(string[] args) { int inteiro = 10; int* pInteiro = &inteiro; *pInteiro = 20; Console.WriteLine( "Endereço da variável pInteiro:\t{0}", (UInt64)pInteiro); Console.WriteLine( "Endereço da variável inteiro:\t{0}", (UInt64)(&inteiro)); Console.WriteLine( "Valor contido no endereço de pInteiro:\t{0}", *pInteiro); Console.WriteLine( "Valor contido na variável inteiro:\t{0}", inteiro); Console.Read(); }

Nesse exemplo, declaramos a variável inteiro e a inicializamos com o valor 10. Na seqüência declaramos o ponteiro pInteiro e o inicializamos com o endereço de memória da variável inteiro.

Nesse momento a variável pInteiro está apontando para o mesmo endereço de memória da variável inteiro. O operador & nos possibilita acessar o endereço de memória e o * possibilita a declaração de um ponteiro e também o acesso ao valor armazenado na memória. Na seqüência, alteramos o valor contido na memória para a qual o ponteiro pInteiro está apontando para 20.

Para finalizar, mostramos o endereço de memória e o valor armazenado.
Compile e execute a aplicação. Podemos ver que tanto a variável pInteiro como a variável inteiro, retornam os mesmos resultados.
Note que este método foi declarado com o modificador unsafe. Experimente remover a palavra chave unsafe e tente compilar a aplicação para ver o erro que o compilador informa.

2º Exemplo:

static void Main(string[] args) { char caractere; Console.Write( "Pressione uma tecla:\t"); caractere = Convert.ToChar( Console.ReadKey().KeyChar); Console.WriteLine(); unsafe { char* pChar = &caractere; Console.WriteLine( "Código ASCII:\t\t{0}", (int)*pChar); Console.WriteLine( "Endereço da variável:\t{0}", (UInt64)(&pChar)); } Console.ReadLine(); }

Nesse exemplo, declaramos uma variável do tipo char com o nome caractere, solicitamos que o usuário digite uma tecla e atribuimos o resultado a nossa variável, na sequência declaramos um ponteiro do tipo char com o nome pChar e atribuimos o endereço de memória da variável caractere para este ponteiro.

Para finalizar este exemplo, convertemos o valor contido no endereço para qual pChar está apontando para um inteiro e mostramos o resultado. A conversão de uma variável do tipo char para um inteiro, retorna o código ASCII deste caractere. Na sequência, mostramos o endereço de memória para qual o ponteiro pChar está apontando.

3º Exemplo:

public struct Pessoa { public enum Gen { Feminino, Masculino } public Gen gen; public int idade; } static unsafe void Main(string[] args) { Pessoa pessoa = new Pessoa(); Pessoa* pPessoa = &pessoa; pPessoa->gen = Pessoa.Gen.Masculino; (*pPessoa).idade = 20; Console.WriteLine("Gen:\t{0}", pPessoa->gen); Console.WriteLine("Idade:\t{0}", (*pPessoa).idade); Console.Read(); }

Nesse exemplo, criamos a estrutura Pessoa com o enum Gen, uma variável do tipo do enum e um inteiro.

No método Main nós criamos uma variável do tipo da estrutura com o nome pessoa e um ponteiro com o nome pPessoa e atribuimos o endereço de memória da variável pessoa. Na sequência atribuimos os valores e mostramos o resultado.

Para acessar um membro de uma estrutura nós podemos utilizar o operador -> ou (*nome_do_ponteiro).membro. Em nosso exemplo, podemos observar essas duas formas de acesso aos membros de uma estrutura, tanto na atribuição como na recuperação do valor. É importante saber que essas formas de acesso retornam os valores e não os endereços de memória.

3 - A Palavra Chave fixed

Antes de analisarmos as necessidades da palavra chave fixed, precisamos entender um pouco da estrutura do .NET Framework e como consequência, analisarmos a necessidade da utilização da palavra chave fixed.

Como vimos na seção Ponteiros, podemos criar ponteiros de vários tipos. Os tipos que vimos, são os Value Types do .NET Framework, ou seja, não podemos criar ponteiros para Reference Types.

Caso você esteja com dúvidas ou ainda não tenha conhecimento sobre os tipos no .NET Framework, o artigo Struct e Class: Quando usar? escrito pelo Renato Guimarães trata este assunto de forma bem clara.

Vejamos o seguinte exemplo:

public struct Pessoa { public int idade; } static unsafe void Main(string[] args) { Pessoa p = new Pessoa(); p.idade = 15; int* pIdade = &p.idade; Console.WriteLine(*pIdade); Console.Read(); }

Neste exemplo, temos a struct Pessoa que contém um membro do tipo inteiro com o nome idade. No método Main, declaramos uma variável do tipo Pessoa e atribuímos um valor para o membro idade. Após isso, declaramos um ponteiro do tipo inteiro e atribuímos o endereço de memória do membro idade.

Agora, vamos transformar a nossa estrutura em uma classe. Esse trabalho é simples, a única coisa que precisamos fazer é substituir a palavra chave struct por class. O nosso código ficará da seguinte forma:

public class Pessoa { public int idade; }

Mantenha o método Main com o mesmo código escrito no exemplo anterior e tente compilar a aplicação.

O nosso código não foi compilado e a seguinte mensagem de erro foi informada:

You can only take the address of an unfixed expression inside of a fixed statement initializer

Nós alteramos a nossa estrutura para uma classe e as classes são Reference Types. Os Reference Types podem ser compostos por um conjunto de Value Types e nós podemos criar ponteiros para estes tipos, inclusive quando eles compõem um Reference Type. Só que a Garbage Collector pode re-alocar essas variáveis na memória, ou seja, se o nosso exemplo anterior compilasse, correríamos o risco de trabalhar com um endereço de memória inválido.


Com a palavra chave fixed, criamos um contexto onde essa variável é fixada, ou seja, durante este contexto ela não é re-alocada pela Garbage Collector. Vamos modificar o método Main incluindo a palavra chave fixed e as chaves que delimitam o seu contexto.


static unsafe void Main(string[] args) { Pessoa p = new Pessoa(); p.idade = 15; fixed (int* pIdade = &p.idade) { Console.WriteLine(*pIdade); } Console.Read(); }

4 - Aritmética de Ponteiros
Na aritmética de ponteiros, as únicas operações possíveis são de soma e subtração e quando ocorre uma dessas operações, o cálculo é feito com base no tipo do ponteiro que estamos trabalhando. Por exemplo: Se temos um ponteiro do tipo inteiro apontando para o endereço de memória 60091584 e subtraímos um ao ponteiro, após essa operação ele estará apontando para 60091580. Esse cálculo é feito de acordo com a quantidade de bytes necessária para a alocação de um valor na pilha ou seja, pode variar de acordo com o tipo de dados que estamos trabalhando.

Vejamos agora um programa em que criamos dois ponteiros do tipo inteiro e trocamos os endereços de memória que eles estão apontando entre eles:

static unsafe void Main(string[] args) { int inteiro1 = 13; int inteiro2 = 25; int* pInteiro1 = &inteiro1; int* pInteiro2 = &inteiro2; Console.WriteLine("Endereço de memória de pInteiro1: {0}", (UInt64)pInteiro1); Console.WriteLine("Endereço de memória de pInteiro2: {0}", (UInt64)pInteiro2); pInteiro1--; pInteiro2++; Console.WriteLine("\nEndereço de memória de pInteiro1: {0}", (UInt64)pInteiro1); Console.WriteLine("Endereço de memória de pInteiro2: {0}", (UInt64)pInteiro2); Console.Read(); }

5 - A Palavra Chave stackalloc
O mecanismo de stackalloc nos permite alocar um bloco de memória na pilha. O retorno é um ponteiro para o bloco de memória alocado. Trabalhamos com este bloco de memória de forma semelhante a um array, através de um índice.

static unsafe void Main(string[] args) { int* buffer = stackalloc int[10]; for (int indice = 0; indice < 10; indice++) { buffer[indice] = indice; Console.WriteLine("Endereço: {0}\tValor: {1}", (UInt64)(&buffer[indice]), buffer[indice]); } Console.Read(); }


Neste artigo, aprendemos a manipular ponteiros na plataforma .NET 2.0. Vimos também onde podemos declarar um código como unsafe, criando um contexto onde é possível usufruir do poder dos ponteiros.


Monday, October 19, 2015

SignalR


ASP.NET SignalR – Introdução e Utilização


O ASP.NET SignalR é uma biblioteca open-source que facilita a implementação de comunicação em tempo real, atualizações/notificações de forma assíncrona em uma aplicação.

Foi desenvolvido por dois funcionários da Microsoft – Damian Edwards e David Fowler, todo o código fonte do projeto está disponível no GitHub
Há um certo tempo foi incorporado pela plataforma ASP.Net, sendo:
ASP.Net SignalR
Funciona através de uma biblioteca Server Side (ASP.Net) e uma Client Side (Javascript), é suportado em aplicações do tipo Silverlight, Windows Phone 7 e 8 e WinRT. Veja a lista completa de plataformas suportadas aqui.
Quem já precisou desenvolver uma aplicação real-time conhece as dificuldades de manter um certo volume de conexões do servidor, manipular a maneira que o servidor trata as requisições, garantir que o client esteja exibindo as informações no tempo certo e enfim.
Existem alguns meios de implementar uma comunicação em tempo real (Long Polling, WebSockets, Node.js) todas essas técnicas/tecnologias possuem sua complexidade ou limitação técnica, o SignalR propõe a facilitar a implementação da comunicação real-time em sua aplicação.
O que é uma aplicação real-time?
É uma aplicação onde a informação chega em tempo real, imagine um chat ou um ticker de cotação da bolsa de valores, essas informações estão sendo distribuídas em tempo real para todos os clientes consumidores da aplicação.
Para se desenvolver uma aplicação em tempo real é necessário que o servidor seja capaz de sensibilizar todos os clientes conectados assim que uma informação chegar.
Como funciona?
O ASP.Net SignalR é uma abstração de uma conexão, ele trabalha por baixo dos panos definindo o melhor tipo de transporte em dois níveis diferentes de abstração o que ocasiona uma impressão de uma conexão persistente.
ASP.Net SignalR
Transportes
Um dos grandes pontos do ASP.Net SignalR é sua capacidade de gerenciar a escolha do tipo de transporte a ser utilizado.
Como mostra a figura existem quatro tipos de transportes disponíveis:
  1. WebSockets
  2. Long Polling
  3. Server Sent Events
  4. Forever Frame
Lendo a documentação do ASP.Net SignalR iremos entender que fica a cargo dele encontrar o transporte mais eficaz entre um server/client, dando sempre preferência por WebSockets quando disponível e caso não esteja disponível parte para Long Polling e os demais em sequência.
WebSocket é uma tecnologia que permite a comunicação bidirecional por canais full-dulplex sobre um único soquete Transmission Control Protocol (TCP). Ela foi projetada para ser executada em navegadores e servidores web que suportem o HTML5, mas pode ser usado por qualquer cliente ou servidor de aplicativos. A API WebSocket está sendo padronizada pelo W3C e o protocolo WebSocket está sendo padronizado pelo IETF.
Sendo assim apesar de termos tipos de transportes variantes o código fonte é sempre o mesmo, a responsabilidade de escolher o tipo de transporte fica por conta do SignalR, porém existe disponível uma maneira de definir o uso de um transporte específico.
Comunicação com PersistentConnection e Hubs
O ASP.Net SignalR oferece dois níveis de abstração de comunicação entre clientes e servidores, sendo o Hubs de alto nível e PersistentConnection de baixo nível.
PersistentConnection representa um endpoint de comunicação com um único destinatário, agrupamentos ou mensagens de broadcast.
É necessário a configuração de uma rota customizada dentro do arquivo Global.asax.
A API de conexão (representada em código .Net pela classe PersistentConnection) dá ao desenvolvedor acesso direto a comunicação de baixo nível que o SignalR expõe, similar a forma de trabalhar com Sockets. O modelo de comunicação PersistentConnection será familiar para os desenvolvedores que usam API’s baseadas em conexão como o Windows Communcation Foundation – WCF.
Hubs é um pipeline de mais alto nível construído sobre a API PersistentConnection  e que permite que o cliente e servidor chamem métodos entre si diretamente.
O SignalR lida com o envio através dos limites da máquina, permitindo que o cliente chame os métodos no servidor tão facilmente como métodos locais e vice-versa.
Se o seu aplicativo usa diferentes tipos de mensagens é recomendável que você use a classe Hub, de modo que você possa chamar métodos no client em vez de enviar uma mensagem explícita que precisa ser recebida, interpretada e posta em prática. Usando o modelo de comunicação Hubs será familiar para os desenvolvedores que usam API’s de invocação remota como. NET Remoting.
A escolha de um modelo de comunicação
A maioria dos aplicativos deve usar o modelo Hubs.
PersistentConnections podem ser utilizados nas seguintes circunstâncias:
  • O formato da mensagem enviada necessita de ser controlado.
  • O desenvolvedor prefere trabalhar com um modelo de envio de mensagens ao invés de um modelo de invocação remota.
  • Um aplicativo existente que usa um modelo de mensagem está sendo portado para usar SignalR.
Como começar?
É necessário o Visual Studio 2010 SP1 ou o Visual Studio 2012
  • Inicie um projeto ASP.Net MVC
  • Instale o ASP.Net SignalR através do Nuget:
Install-Package Microsoft.AspNet.SignalR
  • Adicione um Controller vazio
1public class ChatController : Controller
2{
3    public ActionResult Index()
4    {
5        return View();
6    }
7}
  • Crie uma View
1@{
2    ViewBag.Title = "Chat Básico";
3}
4<label for="apelido" >Seu Apelido:</label><input type="text" name="apelido" id="apelido" /><br />
5<label for="mensagem" >Mensagem:</label><input type="text"name="mensagem" id="mensagem" maxlength="100" />
6<div id="chatWindow" style="width: 100%; height: 300px; overflow: scroll; border: 1px solid grey"></div>
7
8<!-- Referenciando os scripts adicionados ao Bundle -->
9@Scripts.Render("~/bundles/jquery")
10@Scripts.Render("~/bundles/SignalR")
11
12<!-- Referencia para o script de Hub criado automaticamente -->
13<script src="/signalr/hubs" type="text/javascript"></script>
14
15<script type="text/javascript">
16    $(function () {
17        // Declarando um proxy de referencia ao Hub
18        var chatHub = $.connection.chat;
19
20        // Criando a função que será chamada pelo Hub para distribuir as mensagens aos clientes.
21        // Por convenção as chamadas aos métodos são feitas em "camelCase"
22        chatHub.transmitirMensagem = function (apelido, msg) {
23
24            // Area do chat
25            var chatWin = $("#chatWindow");
26
27            // Publicando a mensagem no chat
28            chatWin.html(chatWin.html() + "<b>" + apelido + "</b>: " + msg + "<br />");
29        };
30
31        // Iniciando a conexão com o Hub
32        $.connection.hub.start();
33
34        // Validando o botão enter
35        $(document).keypress(function (e) {
36            if (e.which == 13) {
37
38                // Chamando o método de transmissão de mensagem no Hub
39                chatHub.enviarMensagem($("#apelido").val(), $("#mensagem").val());
40
41                // Limpando o texto da mensagem.
42                $("#mensagem").val("");
43            }
44        });
45    });
46</script>
  • Crie um Hub
1public class Chat : Hub
2{
3    public void EnviarMensagem(string apelido, stringmensagem)
4    {
5        Clients.TransmitirMensagem(apelido, mensagem);
6    }
7 }
Este exemplo está disponível para download aqui.
Ao executar o projeto abra uma segunda instância de um browser (experimente browsers diferentes) e teste a conversação do chat.
ASP.Net SignalR
É incrivelmente fácil, não é mesmo?
O client chama métodos no Hub (server) como se fossem métodos locais e os métodos no server chamam métodos no client como se fossem métodos no servidor.
Quero conhecer e aprender mais!
Leia estes dois sites:
Assista este ótimo vídeo que foi gravado no TechEd 2012 por um dos desenvolvedores do  ASP.Net SignalR.
Leia este Free eBook do MVP JM Aguilar, eu já li e recomendo (inglês)
Mais exemplos para baixar:
Baixou o código fonte e teve alguma dúvida? Colocou a mão na massa e quer conhecer algum detalhe mais profundamente? Os desenvolvedores do ASP.Net SignalR respondem, eles ficam disponíveis neste chat, eu dei meu alô para eles e fui respondido:
ASP.Net SignalR
O exemplo do chat é o mais simples e clássico para usar na comunicação em tempo real, porém as possibilidades de utilização são inúmeras, adicione o ASP.Net SignalR em seu conhecimento técnico e faça proveito.
Este foi um post introdutório, falarei muito mais deste assunto em outros artigos, estou preparando uma aplicação especial para disponibilizar na comunidade utilizando ASP.Net SignalR e também tem minha palestra no Visual Studio Summit 2013 (será gravada e disponibilizada aqui).
Créditos do artigo Eduardo Pires