Sistema de rede
Conecte-se com o .NET Framework 3.5
Mariya Atanasova and Larry Cleeton and Mike Flasko and Amit Paka
Este artigo aborda:
- Desempenho da classe Socket
- URLs internacionalizados
- O namespace System.Net.PeerToPeer
|
Este artigo utiliza as seguintes tecnologias:
.NET Framework
|

Conteúdo
No Microsoft® .NET Framework, o namespace System.Net apresenta a funcionalidade de vários protocolos de rede, como o HTTP e o SMTP. O lançamento do .NET Framework 3.5 (que será fornecido com o Visual Studio® 2008, anteriormente intitulado "Orcas") inclui diversos aprimoramentos funcionais e de desempenho feitos nessas camadas centrais do sistema de rede. Neste artigo, veremos as três principais alterações fornecidas pela equipe do System.Net:
- API de Socket de alto desempenho
- Suporte a identificador de recurso internacionalizado para URIs
- O namespace do P2P (ponto a ponto)
O lançamento do .NET Framework 3.5 apresentará mudanças no próprio Framework. Os recursos descritos neste artigo estão disponíveis na versão Beta 1 do Visual Studio 2008, que pode ser baixada do site do MSDN®.
Desempenho da classe Socket
Na versão 2.0 do .NET Framework, o namespace System.Net.Sockets possui uma classe que oferece virtualmente toda a funcionalidade das APIs Win32
® do Winsock do Windows
®. A funcionalidade vem em uma classe com métodos e propriedades criados para desenvolvedores de código gerenciado. Na classe Socket, existe um conjunto de métodos síncronos, incluindo Send e Receive, com várias sobrecargas de parâmetros para uma variedade de cenários. Esses métodos síncronos são fáceis de usar e muito convenientes para as tarefas simples de sistema de rede que utilizam soquetes. Em Socket, há também um conjunto de métodos assíncronos baseados no APM (modelo de programação assíncrona), que prevalece em todo o .NET Framework (consulte
msdn.microsoft.com/msdnmag/issues/07/03/ConcurrentAffairs para obter mais informações). Esses métodos assíncronos fazem com que a classe Socket seja relativamente fácil de usar de forma assíncrona e oferecem uma forma de manipular vários soquetes ou muitas operações de envio e de recebimento em um grande número de soquetes.
A classe Socket da versão 2.0 é apropriada para uma variedade de aplicativos clientes que precisam usar soquetes de rede assim como para alguns aplicativos de tipo de serviço e de servidor. Infelizmente, existem alguns cenários de aplicativo de serviço que não podem ser reproduzidos com a classe Socket da versão 2.0, mas que são possíveis com linguagens nativas que utilizam as APIs do WinSock do Windows de forma direta. O principal problema da classe Socket da versão 2.0 é que ela consome ciclos de CPU em excesso para executar uma única operação de E/S de soquete, assim como quando aloca os objetos subjacentes necessários para a manutenção de operações de E/S em um grande número de soquetes simultaneamente.
Com o .NET Framework 3.5, o CLR (Common Language Runtime) pode gerenciar de forma mais eficiente um grande número de objetos de Overlapped simultaneamente. Os objetos de Overlapped do CLR contêm efetivamente a estrutura OVERLAPPED nativa do Windows usada no gerenciamento de operações de E/S assíncronas. Existe uma instância do objeto de Overlapped para cada operação de E/S assíncrona de Socket em andamento. E agora é possível haver 60 mil ou mais soquetes conectados enquanto uma operação pendente de E/S de recebimento assíncrono é mantida em cada soquete.
A classe Socket da versão 2.0 usa portas de conclusão de E/S do Windows para o encerramento da operação de E/S assíncrona. Isso permite que aplicativos sejam facilmente dimensionados para um número maior de soquetes abertos. O .NET Framework implementa a classe System.Threading.ThreadPool, que oferece os threads de conclusão que lêem as portas de conclusão e concluem as operações de E/S assíncronas. Ao desenvolvermos a futura versão 3.5 do .NET Framework, nos concentramos significativamente na remoção da sobrecarga dos caminhos de código entre a leitura da porta de conclusão e da chamada a um delegado de conclusão de um aplicativo ou a sinalização do objeto de evento de conclusão de E/S em um objeto de IAsyncResult.
O APM do .NET Framework também é conhecido como o padrão Begin/End. Isso porque um método Begin é chamado para iniciar uma operação assíncrona e retornar um objeto de IAsyncResult. Um delegado pode, opcionalmente, ser oferecido como parâmetro ao método Begin, que será chamado quando a operação assíncrona for concluída. Como alternativa, um thread pode esperar por IAsyncResult.AsyncWaitHandle. Quando o retorno de chamada é feito ou a espera assinalada, o método End é chamado para obter os resultados da operação assíncrona. Esse padrão é flexível, relativamente fácil de usar e muito comum no .NET Framework.
No entanto, é importante observar que existe um preço para a execução de um número significativo de operações de soquete assíncronas. Para cada operação, um objeto de IAsyncResult deve ser criado — e não pode ser reutilizado. Isso pode causar um impacto no desempenho ao exercitar de forma pesada a alocação de objetos e a coleta de lixo. Para contornar esse problema, a nova versão oferece um padrão de métodos diferente para E/S assíncrona com soquetes. Esse novo padrão não requer a alocação de um objeto de contexto de operação para todas as operações de soquetes.
Em vez de criarmos um padrão inteiramente novo, pegamos um padrão existente e fazemos uma alteração fundamental. Agora existem métodos na classe Socket que usam uma variação do modelo de conclusão baseado em Event. Na versão 2.0, você teria de usar o código a seguir para iniciar um envio assíncrono em um Socket:
|
void OnSendCompletion(IAsyncResult ar) { }
IAsyncResult ar = socket.BeginSend(buffer, 0, buffer.Length,
SocketFlags.None, OnSendCompletion, state);
|
Na nova versão, também é possível fazer isto:
|
void OnSendCompletion(object src, SocketAsyncEventArgs sae) { }
SocketAsyncEventArgs sae = new SocketAsyncEventArgs();
sae.Completed += OnSendCompletion;
sae.SetBuffer(buffer, 0, buffer.Length);
socket.SendAsync(sae);
|
Existem algumas poucas diferenças dignas de nota aqui. O objeto que contém o contexto da operação é um objeto de SocketAsyncEventArgs em vez de um objeto de IAsyncResult. O aplicativo cria e gerencia (e pode até reutilizar) objetos de SocketAsyncEventArgs. Todos os parâmetros para a operação de soquete são especificados por propriedades e métodos do objeto de SocketAsyncEventArgs. O status de conclusão também é oferecido por propriedades do objeto de SocketAsyncEventArgs. E, por fim, é necessária a utilização de um método de conclusão de retorno de chamada de um manipulador de eventos.
Todas essas mudanças resultam em um desempenho significativamente aperfeiçoado e na escalabilidade da classe System.Net.Sockets do .NET Framework 3.5. Dois desses aperfeiçoamentos serão automaticamente percebidos pelos aplicativos existentes. O terceiro aperfeiçoamento, os novos métodos de Socket, só podem ser usados para a modificação de um aplicativo, mas eles oferecem uma maior escalabilidade para a maioria dos aplicativos baseados em soquetes mais exigentes.
Suporte a identificador de recurso internacionalizado
Os endereços da Web são normalmente expressos por meio de URIs (identificadores de recurso universal), que consistem em conjuntos de caracteres muito restritos. Basicamente, eles contêm somente as letras maiúsculas e minúsculas do alfabeto do idioma inglês, dígitos de 0 a 9 e um pequeno número de outros símbolos ASCII, incluindo vírgulas e hífens.
A sintaxe não é muito conveniente para as partes do mundo que utilizam um conjunto de caracteres diferente do alfabeto latino — como o japonês ou o hebraico. Considere um endereço como www.BaldwinMuseumOfScience.com. Se você fala inglês, esse endereço é fácil de entender e de lembrar. No entanto, se você não fala inglês, esse URL parece mais com um agrupamento aleatório de símbolos. Se você só fala inglês, seria capaz de se lembrar de um endereço longo em chinês?
Os IRIs (ou identificadores de recurso globais) oferecem suporte a caracteres não ASCII — ou, mais precisamente, caracteres Unicode/ISO 10646. Isso significa que um nome de domínio pode conter caracteres Unicode, fazendo com que você termine com um URL como este: http://微軟香港.com.
Nós estendemos a classe System.Uri existente para oferecermos suporte a IRI com base na RFC 3987 (consulte
faqs.org/rfcs/rfc3987.html). Os usuários atuais não verão qualquer mudança do comportamento do .NET Framework 2.0, a menos que optem especificamente pela habilitação dos recursos IRI. Fizemos isso para garantirmos a compatibilidade de aplicativo entre a versão 3.5 e as anteriores.
Para utilizar esse recurso, você precisa fazer duas mudanças. Primeiro, adicione o elemento a seguir ao arquivo machine.config:
|
<section name="uri" type="System.Configuration.UriSection, System,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
|
Em seguida, especifique se a análise do IDN (nome de domínio internacionalizado) deve ser aplicada ao nome do domínio e se as regras de análise do IRI devem ser usadas. Isso pode ser feito no machine.config de toda a máquina ou em um arquivo app.config do aplicativo individual. Por exemplo:
|
<configuration>
<uri>
<idn enabled="All" />
<iriParsing enabled="true" />
</uri>
</configuration>
|
Habilitar o IDN converterá todos os rótulos Unicode de um nome de domínio para seus equivalentes em Punicode. Os nomes Punicode contêm somente caracteres ASCII e sempre começam com o prefixo "xn--". Isso acontece porque a maioria dos servidores DNS implantados atualmente na Internet só oferecem suporte a caracteres ASCII. A habilitação de IDN só afeta o valor da propriedade Uri.DnsSafeHost. Para 微軟香港.com, ela conterá xn--g5tu63aivy37i.com, enquanto que Uri.Host conterá os caracteres Unicode.
Existem três valores possíveis para IDN que você pode usar no atributo habilitado do elemento idn, dependendo dos servidores DNS que esteja usando:
- "All" usará nomes IDN (Punicode) para todos os domínios.
- "AllExceptIntranet" usará nomes IDN para todos os domínios externos e nomes Unicode para todos os domínios internos. Esse caso só se aplicará quando os servidores DNS da intranet oferecerem suporte a nomes Unicode.
- "None", que é o padrão, é consistente com o comportamento do .NET Framework 2.0.
Habilitar a análise de IRI (iriParsing enabled = "true") faz com que a normalização e a verificação de caracteres sejam feitas de acordo com as regras de IRI mais recentes da RFC 3987. O valor padrão é false e executará a normalização e a verificação de caracteres de acordo com a RFC 2396 (consulte
faqs.org/rfcs/rfc2396.html). Para saber mais sobre os identificadores de recurso universal e sobre a classe Uri, consulte a documentação online em
msdn2.microsoft.com/system.uri.
O namespace System.Net.PeerToPeer
Um novo namespace empolgante adicionado ao .NET Framework 3.5, System.Net.PeerToPeer, está localizado no assembly System.Net.dll e oferece os principais blocos de construção necessários para a criação fácil de um aplicativo P2P (ponto a ponto). O namespace foi criado de acordo com as três fases de um aplicativo P2P típico: descoberta, conexão e comunicação. A fase de descoberta está relacionada à localização dinâmica de itens de mesmo nível e dos locais de rede associados a eles. A fase de conexão lida com o estabelecimento de uma conexão de rede entre itens de mesmo nível. E a fase de comunicação acontece quando os dados são trocados entre os itens de mesmo nível.
Os recursos do namespace System.Net.PeerToPeer oferecem algumas opções que facilitam as fases de descoberta e de conexão. Enquanto isso, tecnologias complementares — como Sockets, HTTPWebRequest e Window Communication Foundation Peer Channel — oferecem soluções para a fase de comunicação.
Antes de haver comunicação entre os itens de mesmo nível, eles devem ser capazes de descobrir uns aos outros e de resolver seus locais de rede (endereços, protocolos e portas) a partir de nomes e de outros tipos de identificadores. A forma como os itens de mesmo nível descobrem uns aos outros e resolvem locais é complicada pela conectividade transitória, pela falta de registros de endereços no DNS e pelos endereços IP dinâmicos.
O recurso PNRP (Peer Name Resolution Protocol), suportado no .NET Framework 3.5, possibilita a descoberta e a comunicação entre itens de mesmo nível ao habilitar a resolução de nomes sem servidor de qualquer recurso para um conjunto de pontos de extremidade de rede. O protocolo PNRP é responsável por duas tarefas fundamentais — publicar um PeerName para que outros o resolvam e resolver um PeerName publicado por outro item de mesmo nível e recuperar os metadados associados (para saber mais sobre como funciona o protocolo PNRP, consulte
microsoft.com/p2p.)
No namespace System.Net.PeerToPeer, um PeerName representa um ponto de extremidade de comunicação, que pode ser qualquer coisa (como um computador, um serviço ou um aplicativo) a que você queira associar metadados. Os PeerNames têm duas formas: protegidos e não protegidos. Um PeerName protegido é apoiado por um par de chaves pública/privada e, quando registrado com o protocolo PNRP, não poderá ser falsificado. Cada cadeia de caracteres de PeerName possui uma seção Authority seguida por um ponto e por uma seção Classifier. Authoritiy é gerado por máquina com base no tipo (protegido ou não protegido) do PeerName, enquanto que o classificador é uma cadeia de caracteres definida pelo usuário.
Para um PeerName protegido, o Framework cria automaticamente uma cadeia de 40 caracteres hexadecimais, como Authority. A cadeia de caracteres hexadecimais é um hash da chave pública associado ao PeerName e é usado para garantir que o registro de tais PeerNames não seja falsificado. Veja como criar um PeerName protegido:
|
PeerName p = new PeerName("My PeerName", PeerNameType.Secured);
|
Para PeerNames não protegidos, o componente Authority será sempre o caractere 0. Um PeerName não protegido é somente uma cadeia de caracteres e não oferece garantias de segurança:
|
PeerName p = new PeerName("My PeerName", PeerNameType.UnSecured);
|
Depois da criação de um PeerName, a próxima etapa será associar o nome a metadados relevantes pela instanciação de um objeto de PeerNameRegistration. Normalmente, um PeerName é associado a um endereço IP mas, como você verá, ele também pode ser associado a uma cadeia de caracteres de comentário e a um blob de dados binários. No trecho de código a seguir, um IPAddress é explicitamente associado ao PeerName pela adição de uma instância de PeerEndPoint à coleção de pontos de extremidade dos registros:
|
PeerName peerName = new PeerName("My PeerName", PeerNameType.Secured);
PeerNameRegistration pnReg = new PeerNameRegistration();
pnReg.PeerName = peerName;
pnReg.EndPointCollection.Add(new IPEndPoint(
IPAddress.Parse("<ip address to associate with the name>"), 5000));
pnReg.Comment = "up to 39 unicode char comment";
pnReg.Data = System.Text.Encoding.UTF8.GetBytes(
"A data blob up to 4K associated with the name");
|
Embora essa seja uma utilização válida da classe PeerNameRegistration, descobrimos que um cenário comum é associar todos os endereços atribuídos à máquina local ao PeerName. Para fazer isso, basta garantir que a propriedade PeerNameRegistration.UseAutoEndPointSelection seja definida como true e evitar a adição de PeerNameRegistration.EndPointCollection.
Agora que todos os metadados relevantes foram atribuídos ao PeerName por meio do objeto PeerNameRegistration, a última etapa é publicar o PeerName em uma nuvem para que os outros itens de mesmo nível possam resolver o nome. No protocolo PNRP, uma nuvem é simplesmente um conjunto de computadores que participa do PNRP e que define o escopo em que os nomes serão publicados ou de onde serão resolvidos. Quando estiver publicando um nome, você precisa determinar a nuvem (ou escopo) em que deseja publicá-lo.
Atualmente, o protocolo PNRP utiliza duas nuvens: vínculo local e global. Um PeerName publicado na nuvem de vínculo local significa que somente os outros itens de mesmo nível do mesmo vínculo poderão resolver o nome. Um nome publicado na nuvem global permite que qualquer um na Internet possa resolver o PeerName. Para publicar um PeerName na nuvem global, basta atribuir a nuvem global, por meio da enumeração Cloud.Global, à propriedade Cloud do objeto de PeerNameRegistration e chamar o método Start no objeto de registro. Quando a chamada ao início for concluída, o nome será publicado e poderá ser resolvido pelos itens de mesmo nível remotos. A Figura 1 mostra o código usado na criação e na publicação de um PeerName.

Figure 1 Criar e publicar um PeerName
|
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.PeerToPeer;
namespace CreateAndPublish
{
class Program
{
static void Main(string[] args)
{
// Creates a secured PeerName.
PeerName peerName = new PeerName(
"MyWebServer", PeerNameType.Secured);
PeerNameRegistration pnReg = new PeerNameRegistration();
pnReg.PeerName = peerName;
pnReg.Port = 80;
//Starting the registration means the name is published
//for other peers to resolve.
pnReg.Start();
Console.WriteLine("Registration of Peer Name: {0} complete.",
peerName.ToString());
Console.WriteLine("Press any key to stop the registration " +
"and close the program");
Console.ReadKey();
pnReg.Stop();
}
}
}
|
Agora que você já viu como criar e publicar um PeerName, precisa saber como resolvê-lo. Comece pela designação de uma instância da classe PeerNameResolver, que será usada para resolver um nome de forma síncrona (consulte a Figura 2) ou assíncrona. Se você estiver resolvendo nomes de forma assíncrona, será importante observar que o mesmo PeerNameResolver pode ser usado na resolução de vários PeerNames. Ou seja, você pode iniciar várias operações de resolução assíncronas para PeerNames diferentes antes da conclusão da primeira operação, eliminando a necessidade de instanciação de um novo objeto resolvedor para cada operação de resolução que esteja acontecendo em paralelo.

Figure 2 Resolução de nomes síncrona
|
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.PeerToPeer;
using System.Net;
namespace SyncResolve
{
class Program
{
// The application accepts the peer name to resolve as the first
// and only command line parameter.
static void Main(string[] args)
{
// Create a resolver object to resolve a peername.
PeerNameResolver resolver = new PeerNameResolver();
PeerName peerName = new PeerName(args[0]);
// Resolve the PeerName - this is a network operation and will
// block until the resolve request is completed.
PeerNameRecordCollection results = resolver.Resolve(peerName);
// Show the data returned by the resolve operation.
Console.WriteLine("Records from resolution of PeerName: {0}",
peerName);
Console.WriteLine();
int count = 1;
foreach (PeerNameRecord record in results)
{
Console.WriteLine("Record #{0} results...", count);
Console.WriteLine("Comment:");
if (record.Comment != null)
{
Console.WriteLine(record.Comment);
}
Console.WriteLine("Data:");
if (record.Data != null)
{
//Assumes the data is an ASCII formatted string
Console.WriteLine(
System.Text.Encoding.ASCII.GetString(record.Data));
}
Console.WriteLine("Endpoints:");
foreach (IPEndPoint endpoint in record.EndPointCollection)
{
Console.WriteLine("\t Endpoint:{0}", endpoint);
Console.WriteLine();
}
count++;
}
Console.ReadKey();
}
}
}
|
Neste ponto, você pode usar o código mostrado na
Figura 1 e na
Figura 2 para tentar criar e resolver PeerNames. Mas observe que, quando você estiver experimentando a funcionalidade do protocolo PNRP, não poderá resolver um PeerName no mesmo processo que publicou o nome. Também devemos mencionar que as APIs do PNRP discutidas aqui usam a infra-estrutura do PNRP do Windows e são suportadas no Windows XP (com a atualização do protocolo PNRP disponível em
support.microsoft.com/kb/920342 instalada), no Windows Vista
® e no Windows Server 2008.
O .NET Framework 3.5 também apresenta o namespace System.Net.PeerToPeer.Collaboration. A colaboração funciona em dois contextos. O primeiro, "Pessoas ao meu Redor", lida com usuários conectados à infra-estrutura de colaboração e localizados na mesma sub-rede (para obter mais detalhes sobre isso, consulte
microsoft.com/technet/network/p2p/pnm.mspx). O outro contexto, conhecido como "Contatos", envolve as pessoas que foram adicionadas ao seu Catálogo de endereços do Windows (que pode ser encontrado no seu diretório Usuários da pasta Contatos). No contexto de Contatos, os usuários não precisam estar na mesma sub-rede.
Ambos os contextos permitem que um usuário compartilhe aplicativos e objetos, envie convites e seja avisado de eventos que envolvam outros usuários. Considere um vendedor que precise "encontrar" seus colegas enquanto aguarda por um vôo no aeroporto. O ideal seria que essa pessoa fosse capaz de ligar seu laptop, abrir seu aplicativo da principal linha de negócios (LOB) da empresa e fazer com que o aplicativo encontrasse, de forma dinâmica, seus colegas, estivessem eles ali no aeroporto ou no escritório. Inicialmente, o aplicativo tem de se conectar à infra-estrutura de Colaboração e especificar o escopo da entrada. Neste exemplo, PeerScope.All inclui os escopos da Internet e dos itens de mesmo nível ao meu redor:
|
PeerCollaboration.Signin(PeerScope.All);
|
Depois de conectado, o aplicativo procura por todas as pessoas que estejam perto do vendedor usando:
|
PeerNearMeCollection peers = PeerCollaboration.GetPeersNearMe();
|
PeerNearMeCollection contém uma instância da classe PeerNearMe para cada item de mesmo nível localizado na mesma sub-rede do chamador. Portanto, agora o aplicativo possui uma lista de todas as "Pessoas ao meu Redor" na forma de instâncias de PeerNearMe. Uma instância de PeerNearMe possui uma propriedade que especifica o local de rede ou o IPEndPoint (endereço IP + porta) do item de mesmo nível remoto.
Para procurar por todos os contatos armazenados no catálogo de endereços do vendedor, o aplicativo precisa obter todos os contatos com as seguintes linhas de código:
|
ContactManager contactManager = PeerCollaboration.ContactManager();
PeerContactCollection contacts = contactManager.GetContacts();
|
ContactManager representa o Catálogo de endereços do Windows, que é o armazenamento de contatos usado pela infra-estrutura System.Net.PeerToPeer.Collaboration.
Agora que uma lista de todos os itens de mesmo nível (consistindo em PeerNearMe e PeerContact) foi gerada, esse vendedor poderá escolher os colegas com que deseja interagir e rapidamente enviar convites a todos. Um convite, no contexto de System.Net.PeerToPeer.Collaboration, é um mecanismo que permite solicitar que um item de mesmo nível remoto inicie um determinado aplicativo. Para estabelecer uma conexão de rede entre dois computadores de mesmo nível, um dos itens de mesmo nível precisa estar escutando ativamente por dados de entrada. Esse mecanismo permite que um item de mesmo nível diga a outro qual é o aplicativo que precisa ser executado.
Digamos que o vendedor de nosso exemplo queira interagir com outro colega usando o aplicativo de LOB da empresa. O vendedor precisa garantir que seu colega esteja executando o aplicativo de LOB. Para isso, ele envia um convite ao colega. Quando o sistema do colega recebe o convite, uma caixa de diálogo é exibida ao usuário, dizendo que uma determinada pessoa deseja que ele inicie um aplicativo específico (consulte a Figure 3). A caixa de diálogo oferece a opção de aceitar ou de rejeitar o convite. Se o destinatário clicar no botão Accept, o aplicativo citado no convite será executado automaticamente em seu PC — nesse caso, o aplicativo de LOB — supondo que ele já esteja instalado.
Figura 3 Convite para executar um aplicativo a partir de um item de mesmo nível (Clique na imagem para aumentar a exibição)
Agora ambos os colegas possuem o aplicativo necessário em execução em seus sistemas e estão prontos para iniciar a colaboração. Nesse ponto, o aplicativo de LOB usa outra tecnologia de sistema de rede (como Window Communication Foundation Peer Channel, Sockets ou HTTP) para a comunicação.
Agora que descrevemos os convites, vamos examinar os detalhes e o código associado necessário para habilitar os convites usando o namespace System.Net.PeerToPeer.Collaboration. No que diz respeito à infra-estrutura P2P, um aplicativo pode ser qualquer executável em sua máquina. Para oferecer suporte a convites, o aplicativo precisa estar registrado na infra-estrutura de colaboração de itens de mesmo nível usando o mesmo GUID tanto na máquina de quem convidou como na de quem foi convidado. Este código mostra como criar e registrar um aplicativo baseado em um executável instalado na máquina local:
|
PeerApplication application = new PeerApplication(
appGuid, "Collaboration Application", bytes, pathToApp,
arguments, PeerScope.Internet);
PeerCollaboration.RegisterApplication(
application, PeerApplicationRegistrationType.AllUsers);
|
Os aplicativos registrados executados por meio de convites podem descobrir que contato ou ponto de extremidade enviou o convite usando PeerCollaboration.ApplicationLaunchInfo. Isso permite que o aplicativo recém-executado saiba que foi aberto a partir de um convite de um item de mesmo nível remoto e, portanto, sabe como se conectar a ele. Um convite pode ser enviado ao chamarmos Invite no objeto de mesmo nível retornado de GetPeersNearMe ou para um contato retornado de GetContacts com Invite, como a seguir:
|
PeerInvitationResponse pir = peerNearMe.Invite(
app, "Hello World", data);
PeerInvitationResponse pir = contact.Invite(
app, "Hello World", data);
|
Digamos que o vendedor esteja se comunicando com um colega no aeroporto e que planeja continuar a conversa mais tarde, quando ambos estiverem em lugares diferentes. Ele deve adicionar essa pessoa como um contato em sua máquina. Isso é feito por meio da classe de mesmo nível retornada da chamada a GetPeersNearMe com peer.AddToContactManager. Depois que o vendedor e seu colega tiverem adicionado um ao outro como contatos, poderão se procurar e interagir em qualquer lugar onde estiverem.
Com as APIs de colaboração do .NET Framework 3.5, também é possível compartilhar dados. Por exemplo, se todos os vendedores da empresa quiserem compartilhar seus cartões de visita eletronicamente, isso pode ser feito por meio dos objetos de mesmo nível. Os objetos de mesmo nível são simplesmente blobs de dados (como um arquivo de imagem) que podem ser exibidos pelos itens de mesmo nível remotos. Os objetos podem ser compartilhados por escopo, especificando Pessoas ao meu Redor para permitir que os usuários da mesma sub-rede vejam os objetos ou, no escopo da Internet, para que os seus contatos possam ver os objetos, a despeito do local onde estejam. Por exemplo, para criar um objeto e compartilhá-lo no escopo Pessoas ao meu Redor, basta fazer isto:
|
PeerObject object = new PeerObject(
objectGuid, bytes, PeerScope.NearMe);
PeerCollaboration.SetObject(object);
|
As notificações de presença e de alteração também são elementos importantes da colaboração P2P. Digamos, por exemplo, que o nosso vendedor queira conversar com seu colega Steve no aeroporto assim que Steve se conectar e estiver disponível. Um evento chamado PeerNearMeChanged é oferecido pela classe PeerNearMe para atualizar itens de mesmo nível na mesma sub-rede. Quaisquer alterações feitas no item de mesmo nível fazem com que o delegado associado seja chamado com a informação alterada. Dessa forma, o vendedor poderá ser notificado quando Steve entrar na rede (ou quando sair). O código necessário é similar ao seguinte:
|
PeerNearMe.PeerNearMeChanged += PeerNearMeChangedCallback;
...
void PeerNearMeChangedCallback(
object sender, PeerNearMeChangedEventArgs args)
{
// Check which PeerNearMe has changed and what the change was
// from the args parameter.
}
|
Alterar notificações para contatos em outro local exige algumas etapas a mais. O processo requer confiança mútua, o que significa que você deve observar o contato e que o usuário deve permitir que você o observe. Assim, primeiro você escolhe observar o contato — chamando o método Subscribe em Contact. Em seguida, o item de mesmo nível que você deseja observar deve adicioná-lo como um Contact e permitir que você o observe — definindo a propriedade SubscribeAllowed como SubscriptionType.Allowed. Depois dessas etapas, você poderá rastrear alterações específicas feitas em nomes, objetos, aplicativos, entre outros, para o item de mesmo nível observado.
Por exemplo, suponha que o nosso vendedor queira conversar com um contato do cliente assim que ele se anunciar como online. O código a seguir permitirá que o vendedor obtenha a alteração de status do cliente necessária:
|
custContact.PresenceChanged += ContactPresenceChangedCallback;
...
void ContactPresenceChangedCallback(
object sender, PresenceChangedEventArgs args)
{
if (args.PeerPresenceInfo.PresenceStatus ==
PeerPresenceStatus.Online)
{
// Start chatting with the customer
}
}
|
Observe que essas informações de alteração podem ser tanto para um objeto como para um aplicativo em particular. Associar um delegado ao evento ObjectChanged na classe PeerObject oferecerá informações sobre quaisquer alterações feitas nesse objeto e sobre o local de onde vem o objeto, como, por exemplo, de um Contact ou de um PeerNearMe. De maneira similar, adicionar um delegado ao evento ApplicationChanged em PeerApplication oferecerá informações sobre quaisquer alterações feitas nesse aplicativo.
Por exemplo, para monitorar mudanças em um determinado aplicativo a partir da lista de aplicativos apresentada por qualquer contato de sua lista de contatos, um delegado precisa ser adicionado ao evento ApplicationChanged de PeerApplication:
|
peerApplication.ApplicationChanged += AppChangedCallback;
...
void AppChangedCallback(
object sender, ApplicationChangedEventArgs args)
{
// Check what the change was and which contact and endpoint it
// originated from the args parameter.
}
|
Agora vamos considerar uma situação em que o vendedor esteja ocupado e, portanto, seu status tem de ser alterado para alertar os itens de mesmo nível de que ele não está disponível imediatamente. Faça isso modificando os dados associados à propriedade PeerCollaboration.LocalPresence, assim:
|
PeerCollaboration.LocalPresenceInfo = new PeerPresenceInfo(
PeerPresenceStatus.Away, "Talking with Customer");
|
Resumindo
Este artigo só oferece um exame rápido dos novos recursos fundamentais de sistema de rede adicionados ao .NET Framework 3.5. Se você não consegue esperar, baixe a versão mais recente do CTP de
msdn2.microsoft.com/aa700831 para experimentá-los. Para se manter atualizado com as últimas notícias sobre System.Net, assim como sobre as tecnologias do Sistema de Rede do Windows, visite o blog da equipe de Windows Network Developer Platform (plataforma do desenvolvedor do sistema de rede do Windows),
blogs.msdn.com/wndp.
Mariya Atanasova é engenheira de design de software de testes da equipe do System.Net. Para entrar em contato com ela, visite seu blog em
blogs.msdn.com/mariya.
Larry Cleeton é engenheiro de design de software da equipe do System.Net. Para entrar em contato com ele, visite seu blog em
blogs.msdn.com/CLRSecurity.
Mike Flasko é o gerente de programa das equipes do System.Net, do Winsock e do Winsock Kernel. Para entrar em contato com ele, visite seu blog em
blogs.msdn.com/mflasko.
Amit Paka é engenheiro de design de software da equipe do System.Net. Para entrar em contato com ele, visite seu blog em
blogs.msdn.com/amitpaka.