2010-05-12 11 views
7

Abbiamo problemi con .NET Remoting. In sostanza, abbiamo un server che registra due TcpChannels con ChannelServices.RegisterChannel():Servizi remoti .NET che commutano da soli i canali

  1. Un ascolto sulla porta 50000
  2. altro in ascolto sulla porta 15000.

Poi abbiamo un cliente che registra un TcpChannel per essere in grado di comunicare con il server. Recuperiamo un un oggetto dal server chiamando Activator.GetObject() con l'URI

"tcp: // serverip: 50000/nomeoggetto"

e questo funziona bene, il client si connette al server sulla porta 50000 e ottiene l'oggetto.

Tuttavia, quando iniziamo a chiamare i metodi su quell'oggetto, la connessione al canale sulla porta 50000 viene interrotta e viene effettuata automaticamente una nuova connessione al canale sulla porta 15000. Questo rappresenta un vero problema per noi dal momento che non vogliamo il traffico sulla porta 15000 perché quel canale potrebbe non essere associato alla stessa scheda di rete del canale porta 50000 sul server o quella porta potrebbe non essere aperta nel firewall, il che causa le chiamate in remoto per fallire naturalmente.

Questo è molto strano per noi dal momento che il client non è a conoscenza nel nostro codice che esiste un altro canale sul server sulla porta 15000 o quale IP ascolta, ma tenta di connettersi ad esso.

Qualsiasi aiuto su questo è molto apprezzato,

Grazie, Casper

Questo è il codice che imposta uno dei canali del server, quello di solito sulla porta 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()); 

Questo è il codice che imposta l'altro canale del server, in genere sulla porta 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. 

Questo è il codice nel client che si connette al server di primo canale, quello che di solito sulla porta 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

Se si dispone di una configurazione di canale nel file app.config, aggiungerla alla domanda. –

+0

Grazie per aver risposto. Non c'è alcuna configurazione di app.config poiché è tutto configurato nel codice. Ho aggiunto quel codice alla domanda ora. – Casper

risposta

7

Abbiamo registrato un caso di supporto con Microsoft a questo proposito e apparentemente, ciò che stiamo facendo qui non è supportato da .NET Remoting. È consentito registrare un solo canale di ciascun tipo in un solo AppDomain. Che cosa fa Remoting è che rimanda l'URI dell'oggetto al client per dirgli dove può accedere all'oggetto in questione. Quando lo fa, guarda attraverso i canali registrati sul server e usa il primo canale che trova lì che corrisponde al tipo richiesto (nel nostro caso: Tcp). In altre parole, userà qualsiasi canale per registrarsi per primo. Non interessa a quale canale è collegato il client.

La soluzione è implementare il proprio IClientChannelSinkProvider sul lato client. Quando si implementa il metodo CreateSink(), è possibile scegliere a quale URL si desidera connettere il client quando si crea il sink da utilizzare.

+0

Grazie per la spiegazione! Abbiamo cercato per un po 'di tempo perché il nostro server non rispondesse sempre correttamente durante la creazione di canali per più NIC. La ragione e la soluzione erano come hai descritto. – Philippe

0

ho stuggle con quelli "backlink" porti pure; Ho pensato che si sarebbe verificato solo se il server vuole inviare qualcosa (anche in una procedura evento). Poiché ho sempre avuto problemi con i firewall, sono passato a GenuineChannels (anche se penso che sia un po 'obsoleto).

+0

Remoting stesso non è aggiornato, sostituito da WCF. –

+0

In effetti lo è. Il codice con cui stiamo avendo problemi è stato riscritto quando .NET Framework 1.0 era appena uscito. Nessuno sembra aver notato questo problema durante tutto questo anno finché uno dei nostri clienti non ha provato a collegare i due canali a diversi adattatori di rete. – Casper

Problemi correlati