Pregunta

Como parte de mi protocolo, me gustaría que el cliente envíe su número de versión cuando se establezca una nueva conexión.Me gustaría que esto se hiciera en un controlador separado en proceso, así que tengan paciencia, ya que puede ser una pregunta bastante básica, pero no estoy seguro de cómo hacerlo.La otra cosa es que me gustaría poder enviar POJO de un lado a otro a través de la conexión (canalización).También me encantaría agregar un controlador de autenticación.De todos modos, en este momento recibo algún tipo de error y estoy bastante seguro de que se debe a que la verificación de la versión no se está digiriendo correctamente desde la canalización.

Básicamente, el código que tengo a continuación está configurado para enviar "Hola mundo", que el servidor imprime después de verificar la versión cuando se establece la conexión.Al menos en teoría, en realidad esto no funciona del todo ;)

Actualmente tengo:

Cliente.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();
    }

    ...
}

VersiónClientHandler.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?

Servidor.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
}

Básicamente, lo que quiero es que el número de versión se pase y valide cuando el canal esté conectado como parte del protocolo de comunicación.Todo hecho automáticamente detrás de escena.De manera similar, me encantaría pasar el mecanismo de autenticación de esta manera.

Vi un código que se parecía un poco a lo que quería hacer con el ejemplo de Secure Chat, pero realmente no pude entenderlo.Cualquier ayuda sobre cómo configurar este código sería muy apreciada.Sé que podría hacerlo todo en un controlador masivo, pero ese es el objetivo del proceso, dividirlo en unidades que tengan sentido lógico.

¿Fue útil?

Solución

¡¡¡Encontré la solución !!!

Hubo varios problemas.

En VersionClientHandler, el nuevo código es:

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 la última línea, e.getChannel().write(version); en lugar de Channels.write(ctx, e.getFuture(), versionBuffer);, no estoy seguro del por qué. De hecho, estoy a punto de empezar a investigar por qué tengo el código de ChannelBuffers allí porque no parece hacer nada ...

En VersionServerHandler.java ahora tengo:

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

Observe que ya no leo el búfer, solo hago e.getMessage() y lo lanzo al tipo correcto de objeto. Por encima de esto, agregué ctx.getPipeline().remove(VersionServerHandler.class); que está ahí para eliminar ese controlador de cualquier procesamiento posterior. Ya no es necesario después de la conexión inicial. Gracias a Dennis por ese consejo.

< wentConclusion

El resto es mucho de lo que esperaba. la clave es que no entendía correctamente cómo leer los búferes y pasar la información. Y los mensajes de error y los ejemplos no eran del todo claros. Tan pronto como agregue los canales POJO de Netty a su canalización, debe comenzar a tratar solo con objetos, para todos los controladores. Me perdí ese. Los conceptos eran correctos, es solo la forma en que traté de leer los datos de los canales lo que estaba mal.

El otro gran consejo fue eliminar los controladores de la canalización si no los necesita después de la conexión inicial. Supongo que lo mismo será cierto para un controlador de autenticación. Sería genial tener una confirmación aquí, pero tendré que averiguarlo más tarde.

Otros consejos

No mencionaste cuál era el error que estás viendo.

En cualquier caso, no recomendaría usar un controlador de canal separado para realizar una verificación de la versión.Principalmente porque la verificación de la versión solo debe tener que suceder una vez, cuando se establece la conexión.También porque creo que los manejadores de canales son los mejores que se oponen con las preocupaciones de la capa de transporte, por ejemplo,.Conversión de bytes en POJOS.

Creé un ejemplo simple: https://github.com/boldt/netty-examples/

Devuelve el número de versión cuando se establece una nueva conexión.Se realiza en un controlador separado que se eliminará de la canalización después de que la versión se escriba en el canal.Luego está el ejemplo de ECHO del tutorial de netty.

A telnet localhost 1234 al servidor muestra la versión inmediatamente.

De esta manera, podría agregar un controlador de autenticación a la canalización detrás del controlador de versiones.

Creo que lo que quieres hacer se puede archivar fácilmente agregando algunos controladores personalizados.Entonces, para la verificación de la versión, puede agregar un controlador que anule channelConnected (....) y haga la verificación allí.Para la autenticación, simplemente agregue otro controlador después de la verificación de la versión que anula el método messageRecieved (....).Una vez completada la autenticación, puede eliminar el controlador de la canalización y volver a agregarlo una vez que lo necesite nuevamente.

El BusinessLogic Handler debería estar en proceso como el último.Solo tenga en cuenta que cualquiera de sus controladores realiza alguna operación de bloqueo, debería pensar en agregar un ExecutionHandler delante de él para asegurarse de que el hilo de ioworker se bloqueará y, por lo tanto, hará que el servidor neto no sea responsable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top