2009-03-31 21 views
9

Me he encontrado con un problema. Soy un poco nuevo en WCF por lo que cualquier ayuda sería muy apreciada.WCF: Net.TCP enlaces múltiples, mismo puerto, diferentes direcciones IP

Aquí está mi código:

public static void StartHosts() 
    { 
     try 
     { 
      // Create a new host 
      ServiceHost host = new ServiceHost(typeof(ServerTasks)); 

      List<IPAddress> ips = new List<IPAddress>(Dns.GetHostAddresses(Dns.GetHostName())); 
      if (IPAddress.Loopback != null) 
       ips.Add(IPAddress.Loopback); 

      ips.RemoveAll(i => i.AddressFamily != AddressFamily.InterNetwork); 

      foreach (var ip in ips) 
      { 
       string uri = string.Empty; 

       // Formulate the uri for this host 
       uri = string.Format(
        "net.tcp://{0}:{1}/ServerTasks", 
        ip.ToString(), 
        ServerSettings.Instance.TCPListeningPort 
       ); 


       // Add the endpoint binding 
       host.AddServiceEndpoint(
        typeof(ServerTasks), 
        new NetTcpBinding(SecurityMode.Transport) { TransferMode = TransferMode.Streamed }, 
        uri 
       ); 

      } 



      // Add the meta data publishing 
      var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>(); 
      if (smb == null) 
       smb = new ServiceMetadataBehavior(); 

      smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 
      host.Description.Behaviors.Add(smb); 

      host.AddServiceEndpoint(
       ServiceMetadataBehavior.MexContractName, 
       MetadataExchangeBindings.CreateMexTcpBinding(), 
       "net.tcp://localhost/ServerTasks/mex" 
      ); 

      // Run the host 
      host.Open(); 
     } 
     catch (Exception exc) 
     { 
      DebugLogger.WriteException(exc); 
     } 
    } 

se produce una excepción en la línea: 'host.Open();'

La excepción es:

System.InvalidOperationException Un registro ya existe para URI 'net.tcp: //192.168.1.45: 4329/ServerTasks'.

Lo que estoy tratando de hacer es enlazar a todas las direcciones de red en la máquina para que las aplicaciones cliente puedan llegar al servicio desde cualquier red en la que lo vean. Cuando ejecuto este código, encuentra e intenta configurar un enlace para aproximadamente 5 IP diferentes, incluyendo 127.0.0.1.

192.168.1.45 es la segunda dirección IP a la que intenta vincularse. En el momento en que arroja la excepción, puedo ver (usando netstat) que el programa se ha vinculado a la primera IP de la lista en el puerto 4329. No hay nada vinculado al puerto 4329 en la dirección mencionada en la excepción.

Lo siento, no hay muchos detalles, quería dar una publicación concisa. Si alguien necesita más información, me complacerá proporcionarla.

Nota: He intentado configurar PortSharingEnabled en true para el NetTcpBinding que se crea dentro del bucle foreach, pero igual experimenté el mismo error.

¡Cualquier ayuda o consejo sería muy apreciado!

Gracias

Respuesta

10

Gracias por la información Corazza!

He descubierto cómo lograr esto. Estaba haciendo esto de la manera incorrecta.

Mi objetivo principal era que el servicio escuchara en cada dirección IP disponible en la máquina. Intentar enlazar a cada dirección individualmente es la forma incorrecta de hacerlo.

En su lugar, solo tenía que vincular el servicio al nombre de host de la máquina (no 'localhost') y WCF escucha automáticamente todos los adaptadores.

Aquí está el código corregido:

public static void StartHosts() 
    { 
     try 
     { 
      // Formulate the uri for this host 
      string uri = string.Format(
       "net.tcp://{0}:{1}/ServerTasks", 
       Dns.GetHostName(), 
       ServerSettings.Instance.TCPListeningPort 
      ); 

      // Create a new host 
      ServiceHost host = new ServiceHost(typeof(ServerTasks), new Uri(uri)); 

      // Add the endpoint binding 
      host.AddServiceEndpoint(
       typeof(ServerTasks), 
       new NetTcpBinding(SecurityMode.Transport) 
         { 
          TransferMode = TransferMode.Streamed 
         }, 
       uri 
      ); 

      // Add the meta data publishing 
      var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>(); 
      if (smb == null) 
       smb = new ServiceMetadataBehavior(); 

      smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 
      host.Description.Behaviors.Add(smb); 

      host.AddServiceEndpoint(
       ServiceMetadataBehavior.MexContractName, 
       MetadataExchangeBindings.CreateMexTcpBinding(), 
       "net.tcp://localhost/ServerTasks/mex" 
      ); 

      // Run the host 
      host.Open(); 
     } 
     catch (Exception exc) 
     { 
      DebugLogger.WriteException(exc); 
     } 
    } 
+1

Enlazar a cada dirección IP individualmente es lo correcto porque de lo contrario su servidor tiene un agujero de seguridad - imagine (improbable) una situación en la que otro servicio se vincule a una dirección IP particular y el mismo puerto mientras su servicio está vinculado a TODAS las direcciones IP . En este caso, imposter obtendrá todas las solicitudes de conexión de los clientes que lleguen a esta dirección IP. – AlexT

2

Mel,

Aunque nunca he intentado esto antes de mí mismo, he aquí algunas muestras de ver que he escuchado antes. Es posible que desee crear su objeto vinculante primero y luego agregar la misma instancia al método AddServiceEndpoint, solo un pensamiento para no crear nuevos enlaces cada vez que recuerdo haber leído en algún lugar que netTCPBindings debería ser una relación 1: 1 con la dirección (a pesar de que estás usando direcciones diferentes).

No creo que tenga que preocuparse por el uso compartido de puertos como la apertura de varios puertos.

Aquí hay una muestra de lo que puede lograr con múltiples puertos.

http://www.aspfree.com/c/a/Windows-Scripting/WCF-and-Bindings/2/

He aquí una buena muestra para el uso en la portsharing NetTcpBinding.

http://blogs.msdn.com/drnick/archive/2006/08/08/690333.aspx

-Bryan

1

Parece que estoy :) poco tarde. Pero de todos modos, hay una manera bastante simple de hacer que Wcf escuche todas las interfaces de red disponibles "net.tcp: //0.0.0.0: 8523/WCFTestService".

Cuestiones relacionadas