2010-05-12 12 views
7

Estamos teniendo un extraño problema con .NET Remoting. Básicamente, tenemos un servidor que registra dos TcpChannels con ChannelServices.RegisterChannel():.NET Remoto conmutando canales por sí mismo

  1. Uno escucha en el puerto 50000
  2. otro escucha en el puerto 15000.

Entonces tenemos un cliente que registra una TcpChannel a ser capaz de comunicarse con el servidor. Recuperamos un objeto desde el servidor llamando Activator.GetObject() con el URI

"tcp: // serverip: 50000/objectname"

y esto funciona bien, el cliente se conecta al servidor en el puerto 50000 y obtiene el objeto.

Sin embargo, cuando comenzamos a llamar a métodos sobre ese objeto, la conexión al canal en el puerto 50000 se interrumpe, y se realiza una nueva conexión al canal en el puerto 15000 automáticamente. Esto nos plantea un problema real, ya que no queremos tráfico en el puerto 15000 porque ese canal puede no estar vinculado al mismo adaptador de red que el puerto 50000 en el servidor o ese puerto puede no estar abierto en el firewall, lo que causa el telecontrol llama a fallar naturalmente.

Esto es muy extraño para nosotros, ya que el cliente no tiene conocimiento en nuestro código de que exista otro canal en el servidor en el puerto 15000 o qué IP escucha, pero intenta conectarse a él.

Cualquier ayuda en esto es muy apreciada,

Gracias, Casper

Este es el código que configura uno de los canales de servidor, el que por lo general en el puerto 50000:

IDictionary props = new Hashtable(); 

props["port"] = m_tcpPort; 
props["name"] = String.Empty; 


BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

m_tcpChannel = new TcpServerChannel(props, /*clientProvider,*/ serverProvider); 
ChannelServices.RegisterChannel(m_tcpChannel, false); 

m_wellKnownObjRef = RemotingServices.Marshal(this, "[email protected]" + m_tcpPort.ToString()); 

Este es el código que configura el otro canal del servidor, generalmente en el puerto 15000:

IDictionary props = new Hashtable(); 

props["name"] = String.Empty; 
props["port"] = ip.Port; 
props["bindTo"] = ip.Address.ToString();      
props["timeout"] = REMOTING_TIMEOUT; // Timeout to prevent hung remoting calls. 

if (!String.IsNullOrEmpty(machineName)) 
{ 
    props["machineName"] = machineName; 
} 

    BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
    serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

    BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

    m_channel = new TcpChannel(props, clientProvider, serverProvider); 
    ChannelServices.RegisterChannel(m_channel, false); 

    m_objRef = RemotingServices.Marshal(this, QueueName); // Queuename is a GUID. 

Este es el código en el cliente que se conecta al primer canal servidor, el que está por lo general en el puerto 50000:

IDictionary props = new Hashtable(); 

props["port"] = 0; 

RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off; 

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

m_tcpChannel = new TcpClientChannel(props, clientProvider/*, serverProvider*/); 
ChannelServices.RegisterChannel(m_tcpChannel, false); 

string address = "tcp://" + profile.RemoteIP + ":" + profile.RemoteTCP; 

m_server = (Kernel)Activator.GetObject(typeof(Server), address + "/[email protected]" + port); 
+0

Si tiene alguna configuración de canal en el archivo app.config, agréguela a su pregunta. –

+0

Gracias por responder. No hay configuración de app.config, ya que todo está configurado en el código. He agregado ese código a la pregunta ahora. – Casper

Respuesta

7

Hemos registrado un caso de soporte con Microsoft sobre esto y aparentemente, lo que estamos haciendo aquí no es compatible con .NET Remoting. Solo se le permite registrar un canal de cada tipo en un dominio de aplicación. Lo que hace Remoting es que devuelve el URI del objeto al cliente para indicarle dónde puede acceder al objeto en cuestión. Cuando lo hace, busca a través de los canales registrados en el extremo del servidor y utiliza el primer canal que encuentra allí que coincide con el tipo solicitado (en nuestro caso: Tcp). En otras palabras, usará cualquier canal que ocurra para registrarse primero. No le importa en absoluto sobre qué canal se ha conectado el cliente.

La solución es implementar su propio IClientChannelSinkProvider en el lado del cliente. Cuando implemente el método CreateSink(), puede elegir a qué url quiere que se conecte el cliente cuando crea el receptor a usar.

+0

¡Gracias por la explicación! Hemos estado buscando bastante tiempo por qué nuestro servidor no siempre respondía correctamente al crear canales para múltiples NIC. El motivo y la solución fueron los que describiste. – Philippe

0

Yo stuggle con los "backlinked" puertos así; Pensé que solo ocurriría si el servidor quiere enviar algo a cambio (incluso en un evento-procedimiento). Como siempre tuve problemas con los firewalls, cambié a GenuineChannels (aunque creo que está un poco desactualizado).

+0

Remoting en sí ya no está actualizado, reemplazado por WCF. –

+0

De hecho lo es. El código con el que estamos teniendo problemas se escribió cuando acababa de aparecer .NET Framework 1.0. Nadie parece haber notado este problema durante todos estos años hasta que uno de nuestros clientes intentó unir los dos canales a diferentes adaptadores de red. – Casper

Cuestiones relacionadas