2010-05-12 12 views
7

Nous avons un problème étrange avec .NET Remoting. Fondamentalement, nous avons un serveur qui enregistre deux TcpChannels avec ChannelServices.RegisterChannel():.NET Remoting canaux de commutation par lui-même

  1. On écoute sur le port 50000
  2. Autre une écoute sur le port 15000.

Nous avons alors un client qui enregistre un TcpChannel à être capable de communiquer avec le serveur. Nous récupérons un objet à partir du serveur en appelant Activator.GetObject() avec l'URI

"tcp: // serverip: 50000/objectname"

et cela fonctionne très bien, le client se connecte au serveur sur le port 50000 et obtient l'objet. Toutefois, lorsque nous commençons à appeler des méthodes sur cet objet, la connexion au canal sur le port 50000 est abandonnée et une nouvelle connexion est établie automatiquement sur le canal sur le port 15000. Cela pose un réel problème pour nous car nous ne voulons pas de trafic sur le port 15000 car ce canal peut ne pas être lié à la même carte réseau que le port 50000 sur le serveur ou ce port peut ne pas être ouvert dans le pare-feu. les appels à distance pour échouer naturellement.

Ceci est très étrange pour nous puisque le client n'a aucune connaissance dans notre code qu'il existe un autre canal sur le serveur sur le port 15000 ou sur quelle IP il écoute, mais il tente de s'y connecter.

Toute aide à ce sujet est très apprécié,

Merci, Casper

Voici le code qui met en place l'un des canaux de serveur, celui habituellement sur le port 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()); 

Il s'agit du code qui configure l'autre canal du serveur, généralement sur le port 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. 

C'est le code dans le client qui se connecte au premier canal du serveur, celui qui est habituellement sur le port 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 vous avez une configuration de canal dans le fichier app.config, ajoutez-la à votre question. –

+0

Merci d'avoir répondu. Il n'y a pas de configuration app.config car tout est configuré dans le code. J'ai ajouté ce code à la question maintenant. – Casper

Répondre

7

Nous avons enregistré un cas de support avec Microsoft à ce sujet et apparemment, ce que nous faisons ici n'est pas supporté par .NET Remoting. Vous n'êtes autorisé à enregistrer qu'une seule chaîne de chaque type dans un AppDomain. Ce que Remoting fait est qu'il renvoie l'URI de l'objet au client pour lui dire où il peut accéder à l'objet en question. Quand il le fait, il regarde à travers les canaux enregistrés à la fin du serveur et utilise le premier canal qu'il trouve là qui correspond au type demandé (dans notre cas: Tcp). En d'autres termes, il utilisera n'importe quel canal pour être enregistré en premier. Il ne se soucie pas du canal sur lequel le client s'est connecté.

La solution consiste à implémenter votre propre IClientChannelSinkProvider côté client. Lorsque vous implémentez la méthode CreateSink(), vous pouvez choisir l'URL à laquelle le client doit se connecter lorsque vous créez le récepteur à utiliser.

+0

Merci pour l'explication! Nous avons cherché pendant un certain temps pourquoi notre serveur ne répondait pas toujours correctement lors de la création de canaux pour plusieurs NIC. La raison et la solution étaient comme vous l'avez décrit. – Philippe

0

Je ne stuggle avec les « backlinked » ports ainsi; Je pensais que cela ne se produirait que si le serveur voulait renvoyer quelque chose (même dans une procédure événementielle). Parce que j'avais toujours des problèmes avec les firewalls, je suis passé à GenuineChannels (même si je pense que c'est un peu dépassé).

+0

Remoting lui-même est maintenant obsolète, remplacé par WCF. –

+0

En effet, c'est. Le code avec lequel nous rencontrons des problèmes a été réécrit lorsque .NET Framework 1.0 venait de sortir. Personne ne semble avoir remarqué ce problème pendant toutes ces années jusqu'à ce qu'un de nos clients essaye de lier les deux canaux à différents adaptateurs de réseau. – Casper