Pergunta

Estamos tendo um problema estranho com o .NET remoto. Basicamente, temos um servidor que registra dois TCPChannels com ChannelServices.RegisterChannel():

  1. Um ouve na porta 50000
  2. Outro ouve na porta 15000.

Em seguida, temos um cliente que registra um TCPChannel para poder se comunicar com o servidor. Recuperamos um objeto do servidor ligando Activator.GetObject() com o URI

"TCP: // Serverip: 50000/ObjectName"

E isso funciona bem, o cliente se conecta ao servidor na porta 50000 e recebe o objeto.

No entanto, quando começamos a chamar métodos nesse objeto, a conexão com o canal na porta 50000 é descartada e uma nova conexão é feita no canal na porta 15000 automaticamente. Isso representa um problema real para nós, pois não queremos tráfego na porta 15000 porque esse canal pode não estar vinculado ao mesmo adaptador de rede que o canal da porta 50000 no servidor ou que a porta pode não estar aberta no firewall, o que causa as chamadas remotas para falhar naturalmente.

Isso é muito estranho para nós, pois o cliente não tem conhecimento em nosso código de que existe outro canal no servidor na porta 15000 ou em que IP ele ouve, mas ele tenta se conectar a ele.

Qualquer ajuda nisso é muito apreciada,

Obrigado, Casper

Este é o código que configura um dos canais do servidor, o geralmente na 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, "Server@" + m_tcpPort.ToString() );

Este é o código que configura o outro canal do servidor, geralmente na 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.

Este é o código no cliente que se conecta ao primeiro canal do servidor, o que geralmente está na 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 + "/Server@" + port);
Foi útil?

Solução

Registramos um caso de suporte na Microsoft sobre isso e, aparentemente, o que estamos fazendo aqui não é suportado pelo .NET Remoting. Você só tem permissão para registrar um canal de cada tipo em um aplicativo. O que o remoto faz é que ele envia de volta o URI do objeto ao cliente para dizer onde ele pode acessar o objeto em questão. Quando faz isso, examina os canais registrados na extremidade do servidor e usa o primeiro canal que encontra lá que corresponde ao tipo solicitado (no nosso caso: TCP). Em outras palavras, ele usará o canal que acontecerá primeiro se registrar. Não se importa com o que o canal o cliente conectou.

A solução é implementar seu próprio iClientChannelsinkProvider no lado do cliente. Quando você implementa o método CreateSink (), você pode escolher qual URL deseja que o cliente se conecte ao criar o coletor para usar.

Outras dicas

Eu também lutei com aqueles portos "em backlink"; Eu pensei que isso ocorreria apenas se o servidor quiser enviar algo de volta (mesmo em um processo de evento). Como eu sempre tive problemas com os firewalls, mudei para os genuinechannels (embora eu ache que isso esteja um pouco desatualizado).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top