Pipeline con netty

De ChuWiki
Revisión del 15:52 3 ago 2018 de Chudiang (Discusión | contribuciones) (Frame Extractor)

Saltar a: navegación, buscar

Al final de Ejemplo Sencillo de TCP/IP con netty vimos que Netty permitía que trataramos los bytes recibidos por el socket en partes, de forma que cada uno de nuestros trozos de código haga algo con los bytes recibidos y pase los resultados al siguiente trozo. Vamos a ver aquí todo esto con detalle.

Tienes todo el código de este ejemplo en Ejemplo con netty

Tratamiento de la entrada : ChannelInboundHandler

Cuando llega un array de bytes por el socket, lo más frecuente es tener los siguientes tres trozos de código :

  • Si el que nos envía mensajes lo hace muy seguido, posiblmente recibamos todos los bytes de todos los mensajes seguidos. El primer bloque de código en recepción suele encargarse de separar los bytes que componen cada mensaje para pasarle al siguiente bloque sólo los bytes de un mensaje. Por ejemplo, si los mensajes son líneas de texto separadas por retornos de carro, el primer bloque separa las línesa, buscando los retornos de carro y enviando al siguiente bloque sólo una línea cada vez. Este bloque suele llamarse "extractor de tramas" o "Frame Extractor".
  • El segundo bloque, con la garantía de que el array de bytes que recibe es un mensaje completo en sí mismo, suele traducir estos bytes a una clase java o algo más legible por el código que un array de bytes. En el caso anterior, cogería los bytes de una línea y la convertiría en un String. Este bloque de código se suele llamar "Decodificador" o "Decoder".
  • El tercer bloque es el que hace realmente algo útil con los datos recibidos y ya convertidos en algo legible. Muestra el String por pantalla, o lo interpreta como un comando a ejecutar, o lo que sea que toque hacer con ese String en nuestra aplicación. Este bloque es el de lógica de la aplicación.

En Netty implementamos cada uno de estos bloques haciendo una clase que implemente ChannelInboundHandler, o si no queremos sobreescribir todos sus métodos, heredamos de ChannelInboundHandlerAdapter.

Aunque el extraer mensajes buscando retornos de carro y el convertir bytes a String ya los tiene netty implementados, vamos a hacerlos aquí a mano para mostrar el funcionamiento de esto. Vamos con el primero, el FrameExtractor

Frame Extractor

El código puede ser como el siguiente

package com.chuidiang.examples4;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

public class FrameExtractor extends ChannelInboundHandlerAdapter{

    private ByteBuf buf;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        buf= ctx.alloc().buffer();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        if(null!=buf) {
            buf.release();
            buf=null;
        }

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            buf.writeBytes((ByteBuf) msg);
            int indexOf = buf.indexOf(0, buf.readableBytes(), (byte) '\n');
            while (-1!=indexOf) {
                    ByteBuf line = ctx.alloc().buffer();
                    buf.readBytes(line, indexOf);
                    buf.readByte(); // Leemos el retorno de carro para eliminarlo.
                    ctx.fireChannelRead(line);
                    buf.discardReadBytes();

            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
}