Exemplo de compartilhamento de porta Net.TCP

Este artigo descreve o exemplo de PortSharing.

O protocolo TCP/IP usa um número de 16 bits, chamado de porta, para diferenciar conexões com vários aplicativos de rede em execução no mesmo computador. Se um aplicativo estiver escutando em uma porta, todo o tráfego TCP destinado a ela é enviado ao aplicativo. Outros aplicativos não podem escutar nessa porta ao mesmo tempo.

Muitos protocolos têm um número de porta padrão que é usado. Por exemplo, o protocolo HTTP normalmente usa a porta TCP 80. O IIS (Serviços de Informações da Internet) tem um ouvinte para compartilhar uma porta entre vários aplicativos HTTP. O IIS escuta diretamente na porta e encaminha mensagens ao aplicativo apropriado com base nas informações do fluxo de mensagens. Isso permite que vários aplicativos HTTP usem o mesmo número de porta sem precisar competir para reservar a porta para receber mensagens.

O compartilhamento de porta NetTcp é um recurso do WCF (Windows Communication Foundation) que permite que vários aplicativos de rede compartilhem uma única porta. O serviço de compartilhamento de porta NetTcp aceita conexões usando o protocolo net.tcp e encaminha as mensagens com base no endereço de destino delas.

Ele não é habilitado por padrão. Antes de executar este exemplo, habilite manualmente o serviço. Para saber mais, confira Como habilitar o serviço de compartilhamento de porta Net.TCP. Se o serviço estiver desabilitado, uma exceção será gerada quando o aplicativo do servidor for iniciado.

Unhandled Exception: System.ServiceModel.CommunicationException: The TransportManager failed to listen on the supplied URI using the NetTcpPortSharing service: failed to start the service because it is disabled. An administrator can enable it by running 'sc.exe config NetTcpPortSharing start= demand'.. ---> System.InvalidOperationException: Cannot start service NetTcpPortSharing on computer '.'. ---> System.ComponentModel.Win32Exception: The service cannot be started, either because it is disabled or because it has no enabled devices associated with it

O compartilhamento de porta é habilitado no servidor definindo a propriedade PortSharingEnabled da associação NetTcpBinding ou do elemento de associação TcpTransportBindingElement. O cliente não precisa saber como o compartilhamento de porta foi configurado para usá-lo no servidor.

Habilitar o compartilhamento de porta

O código a seguir demonstra como habilitar o compartilhamento de porta no servidor. Ele inicia uma instância do serviço ICalculator em uma porta fixa com um caminho de URI aleatório. Embora dois serviços possam compartilhar a mesma porta, seus endereços gerais de ponto de extremidade ainda devem ser exclusivos a fim de que o serviço de compartilhamento de porta NetTcp possa rotear mensagens para o aplicativo correto.

// Configure a binding with TCP port sharing enabled
NetTcpBinding binding = new NetTcpBinding();
binding.PortSharingEnabled = true;

// Start a service on a fixed TCP port
ServiceHost host = new ServiceHost(typeof(CalculatorService));
ushort salt = (ushort)new Random().Next();
string address = $"net.tcp://localhost:9000/calculator/{salt}";
host.AddServiceEndpoint(typeof(ICalculator), binding, address);
host.Open();

Com o compartilhamento de porta habilitado, é possível executar o serviço várias vezes sem ter um conflito sobre o número da porta. Se você alterar o código para desabilitar o compartilhamento de porta, iniciar duas cópias do serviço resultará na segunda falha com um AddressAlreadyInUseException.

Unhandled Exception: System.ServiceModel.AddressAlreadyInUseException: There is already a listener on IP endpoint 0.0.0.0:9000. Make sure that you are not trying to use this endpoint multiple times in your application and that there are no other applications listening on this endpoint. ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted

Executando o exemplo

É possível usar o cliente de teste para verificar se as mensagens foram roteadas corretamente para os serviços que compartilham a porta.

class client
{
   static void Main(string[] args)
   {
      Console.Write("Enter the service number to test: ");
      ushort salt = ushort.Parse(Console.ReadLine());
      string address = $"net.tcp://localhost:9000/calculator/{salt}";
      ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(new NetTcpBinding());
      ICalculator proxy = factory.CreateChannel(new EndpointAddress(address));

      // Call the Add service operation.
      double value1 = 100.00D;
      double value2 = 15.99D;
      double result = proxy.Add(value1, value2);
      Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

      // Call the Subtract service operation.
      value1 = 145.00D;
      value2 = 76.54D;
      result = proxy.Subtract(value1, value2);
      Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

      // Call the Multiply service operation.
      value1 = 9.00D;
      value2 = 81.25D;
      result = proxy.Multiply(value1, value2);
      Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

      // Call the Divide service operation.
      value1 = 22.00D;
      value2 = 7.00D;
      result = proxy.Divide(value1, value2);
      Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

      Console.WriteLine();
      Console.WriteLine("Press <ENTER> to terminate client.");
      Console.ReadLine();

      factory.Close();
   }
}

Cada instância do serviço imprime seu número e endereço exclusivos. Por exemplo, você pode ver o texto a seguir ao executar service.exe.

Service #4381 listening on net.tcp://localhost:9000/calculator/4381.
Press <ENTER> to terminate service.

Insira o número de serviço que você vê aqui ao executar client.exe.

Enter the service number to test: 4381
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

Este exemplo pode ser executado em uma configuração entre computadores alterando o endereço gerado que o cliente usa. No Client.cs, altere a cadeia de caracteres de formato de endereço do ponto de extremidade para corresponder ao novo endereço do serviço. Substitua todas as referências a "localhost" pelo endereço IP do computador do servidor. Você deve recompilar o exemplo depois de fazer essa alteração.

Para configurar, compilar, e executar o exemplo

  1. Instale o ASP.NET 4.0 usando o seguinte comando.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Verifique se você executou o Procedimento de instalação única dos exemplos do Windows Communication Foundation.

  3. Habilite o serviço de compartilhamento de porta NetTcp, conforme descrito anteriormente na seção de introdução.

  4. Para compilar a edição .NET de C# ou Visual Basic da solução, siga as instruções contidas em Como compilar os exemplos do Windows Communication Foundation.

  5. Para executar o exemplo em uma configuração de computador único ou entre computadores, siga as instruções contidas em Como executar os exemplos do Windows Communication Foundation. Detalhes específicos para executar este exemplo foram incluídos anteriormente na seção “Execução do exemplo”.