Pergunta

Como parte do meu protocolo, gostaria que o cliente enviasse seu número de versão quando uma nova conexão for estabelecida. Gostaria que isso fosse feito em um manipulador separado no pipeline, portanto, tenha paciência comigo, pois essa pode ser uma questão bastante básica, mas não tenho certeza de como fazer isso. A outra coisa é que eu gostaria de poder enviar POJO's para frente e para trás através da conexão (pipeline). Também adoraria adicionar um manipulador de autenticação. De qualquer forma, agora estou recebendo algum tipo de erro e tenho quase certeza de que é porque a verificação de versão não está sendo digerida corretamente no pipeline.

Basicamente, o código que tenho abaixo está configurado para enviar "Hello World", que o servidor imprime depois que a versão foi verificada quando a conexão foi estabelecida. Pelo menos em teoria, na realidade isso não está funcionando bem;)

Atualmente tenho:

Client.java

public static void main(String[] args)
{
    ...

    // Set up the pipeline factory.
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() 
    {
        @Override
        public ChannelPipeline getPipeline() throws Exception 
        {
            return Channels.pipeline(
                    new ObjectEncoder(),
                    new ObjectDecoder(),
                    new VersionClientHandler(),
                    new BusinessLogicClientHandler());
        }
    });     

    ...

    // The idea is that it will all be request and response. Much like http but with pojo's. 
    ChannelFuture lastWriteFuture = channel.write("Hello world".getBytes());

    if (lastWriteFuture != null) 
    {
        System.out.println("waiting for message to be sent");
           lastWriteFuture.awaitUninterruptibly();
    }

    ...
}

VersionClientHandler.java

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
    versionBuffer.writeBytes("v123.45a".getBytes());
    // If I understand correctly, the next line says use the rest of the stream to do what you need to the next Handler in the pipeline?
    Channels.write(ctx, e.getFuture(), versionBuffer);  
}

BusinessLogicClientHandler.java

Not really doing anything at this point. Should it?

Server.java

public static void main(String[] args)
{
    ...

    public ChannelPipeline getPipeline() throws Exception 
    {
        return Channels.pipeline(
                new ObjectEncoder(),
                new ObjectDecoder(),
                new VersionServerHandler(),
                new BusinessLogicServerHandler());
    }

    ...
}

VersionServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_NUMBER_MAX_SIZE);
    System.out.println("isReadable - messageReceived: " + versionBuffer.readable()); // returns false???
    // Basically I want to read it and confirm the client and server versions match.
    // And if the match fails either send a message or throw an exception
    // How do I also pass on the stream to the next Handler? 
}

BusinessLogicServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}

Basicamente, o que eu quero é que o número da versão seja passado e validado quando o canal for conectado como parte do protocolo de comunicação. Tudo feito automaticamente nos bastidores. Da mesma forma, adoraria passar o mecanismo de autenticação dessa forma.

Eu vi um código que se parecia um pouco com o que eu queria fazer com o exemplo do Secure Chat, mas não consegui descobrir. Qualquer ajuda sobre como configurar este código seria muito apreciada. Eu sei que poderia fazer tudo em um manipulador enorme, mas esse é o objetivo do pipeline, dividi-lo em unidades que façam sentido lógico.

Foi útil?

Solução

Encontrei a solução !!!

Houve vários problemas.

Em VersionClientHandler, o novo código é:

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
{
    String verison = "v123.45a";

    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
    versionBuffer.writeBytes(version.getBytes());
    e.getChannel().write(version);
}

Observe a última linha, e.getChannel().write(version); em vez de Channels.write(ctx, e.getFuture(), versionBuffer);. Não tenho certeza do porquê. Na verdade, estou prestes a começar a pesquisar por que tenho o código ChannelBuffers lá, porque ele parece não fazer nada ...

Em VersionServerHandler.java agora tenho:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    String versionCheck = (String)e.getMessage();
    System.out.println("VersionServerHandler - " + versionCheck);
    ctx.getPipeline().remove(VersionServerHandler.class);
}

Observe que não leio mais o buffer, apenas executo e.getMessage() e faço o cast para o tipo correto de objeto. Acima disso, adicionei ctx.getPipeline().remove(VersionServerHandler.class);, que existe para remover esse manipulador de qualquer processamento posterior. Não é mais necessário após a conexão inicial. Obrigado a Dennis por essa dica.

O resto é o que eu esperava. a chave é que eu não estava entendendo corretamente como ler os buffers e passar as informações. E as mensagens de erro e os exemplos não eram muito claros. Assim que você adiciona os canais POJO do Netty ao seu pipeline, precisa começar a lidar apenas com objetos, para todos os manipuladores. Eu perdi aquele. Os conceitos estavam certos, é apenas como tentei ler os dados dos canais que estavam errados.

A outra grande dica era remover os manipuladores do pipeline se você não precisar deles após a conexão inicial. Presumo que o mesmo seja verdadeiro para um manipulador de autenticação. Seria ótimo ter uma confirmação aqui, mas terei que descobrir isso mais tarde.

Outras dicas

Você não mencionou qual foi o erro que está vendo.

Em qualquer caso, eu não recomendaria usar um manipulador de canal separado para fazer uma verificação de versão.Principalmente porque a verificação de versão deve acontecer apenas uma vez, quando a conexão for estabelecida pela primeira vez.Também porque acho que é melhor deixar os gerenciadores de canal lidando com as questões da camada de transporte, por exemploconverter bytes em pojos.

Acho que o que você deseja fazer pode ser arquivado facilmente adicionando alguns manipuladores personalizados.Portanto, para a verificação de versão, você pode adicionar um manipulador que substitua channelConnected (....) e faça a verificação lá.Para autenticação, basta adicionar outro manipulador após a verificação de versão que substitui o método messageRecieved (....).Depois que a autenticação for concluída, você pode remover o manipulador do pipeline e adicioná-lo de volta quando precisar dele novamente.

O BusinessLogic Handler deve ficar no pipeline como o último.Esteja ciente de que qualquer um de seus manipuladores faz alguma operação de bloqueio, você deve pensar em adicionar um ExecutionHandler na frente dele para ter certeza de que o thread do ioworker será bloqueado e tornará o servidor netty irresponsável.

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