Descrição da classe do núcleo comum do Netty

MessageToByteEncoder

MessageToByteEncoder é um codificador abstrato e as subclasses podem substituir o método encode para codificar objetos na saída ByteBuf.

MessageToByteEncoder herda de ChannelOutboundHandlerAdapter, encode é chamado na saída.

public class MyMessageEncoder extends MessageToByteEncoder<MessagePO> {
    
    
    @Override
    protected void encode(ChannelHandlerContext ctx, MessagePO msg, ByteBuf out) throws Exception {
    
    
        System.out.println("MyMessageEncoder.encode,被调用");
        String json = JSONObject.toJSONString(msg);
        out.writeInt(json.getBytes(StandardCharsets.UTF_8).length);
        out.writeBytes(json.getBytes(StandardCharsets.UTF_8));
    }
}

ByteToMessageDecoder

ByteToMessageDecoder é um ChannelInboundHandler, que pode ser chamado de decodificador, e é responsável por converter o fluxo de bytes (ByteBuf) em uma Message.Message é um objeto Java que a própria aplicação pode definir.

ByteToMessageDecoder: Utilizado para converter bytes em mensagens, é necessário verificar se há bytes suficientes no buffer.

public class MyMessageDecoder extends ByteToMessageDecoder {
    
    
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    
    
        System.out.println("MyMessageDecoder.decode,被调用");
        while (in.readableBytes() >= 4){
    
    
            int num = in.readInt();
            System.out.println("解码出一个整数:"+num);
            out.add(num);
        }
    }
}

ReplayingDecoder

ReplayingDecoder: Herdado de ByteToMessageDecoder, não há necessidade de verificar se há bytes suficientes no buffer, mas ReplayingDecoder é um pouco mais lento que ByteToMessageDecoder e nem todos os ByteBufs o suportam.

Use ReplayingDecoder se a complexidade do projeto for alta, caso contrário, use ByteToMessageDecoder.

public class MyMessageDecoder extends ReplayingDecoder<Void> {
    
    
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    
    
        System.out.println("MyMessageDecoder.decode,被调用");
        int length = in.readInt();
        byte[] content = new byte[length];
        in.readBytes(content);
        String json = new String(content,StandardCharsets.UTF_8);
        MessagePO po = JSONObject.parseObject(json,MessagePO.class);
        out.add(po);
    }
}

MessageToMessageEncoder

Usado para codificar de uma mensagem para outra, como de POJO para POJO, é um ChannelOutboundHandler

MessageToMessageDecoder

A decodificação de uma mensagem para outra, como POJO para POJO, é um ChannelInboundHandler

MessageToMessageCodec

MessageToMessageEncoder e MessageToMessageDecoder integrados

public class RequestMessageCodec extends MessageToMessageCodec<String, RequestData> {
    
    
    @Override
    protected void encode(ChannelHandlerContext ctx, RequestData msg, List<Object> out) throws Exception {
    
    
        System.out.println("RequestMessageCodec.encode 被调用 " + msg);
        String json = JSONObject.toJSONString(msg);
        out.add(json);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, String msg, List<Object> out) throws Exception {
    
    
        System.out.println("RequestMessageCodec.decode 被调用 " + msg);
        RequestData po = JSONObject.parseObject(msg, RequestData.class);
        out.add(po);
    }
}

ChannelInitializer

ChannelInitializer é um ChannelInboundHandler especial que pode inicializar o Canal de forma simples (chamando o método initChannel).

Normalmente defina ChannelPipeline para Channel in Bootstrap.handler(ChannelHandler), eServerBootstrap.handler(ChannelHandler) .ServerBootstrap.childHandler(ChannelHandler)

Nota: Quando o initChannel for executado, o manipulador atual será removido do Pipeline.

Bootstrap bootstrap = new Bootstrap().group(group)//设置线程组
    .channel(NioSocketChannel.class)//设置客户端通道的实现类
    .handler(new ChannelInitializer<SocketChannel>() {
    
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
    
    
            ch.pipeline().addLast(new NettyClientHandler());//加入自己的处理器
        }
    });
ServerBootstrap bootstrap = new ServerBootstrap().group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)//使用NioServerSocketChannel作为服务器的通道实现
    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列等待连接的个数
    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
//      .handler(null)//该Handler对应bossGroup
    .childHandler(new ChannelInitializer<SocketChannel>() {
    
    //给workerGroup的EventLoop对应的管道设置处理器
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
    
    
            ch.pipeline().addLast(new NettyServerHandler());
        }
    });

SimpleChannelInboundHandler

SimpleChannelInboundHandler herda de ChannelInboundHandlerAdapter e pode especificar o tipo de mensagem por meio de genéricos.
Para processar os dados recebidos, precisamos apenas implementar o método channelRead0.
SimpleChannelInboundHandler liberará automaticamente o recurso Bytebuffer ocupado pelos dados após receber os dados, enquanto ChannelInboundHandlerAdapter não o liberará automaticamente.

public class MyClientHandler extends SimpleChannelInboundHandler<MessagePO> {
    
    

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessagePO msg) throws Exception {
    
    
        System.out.println("收到服务端消息:" + msg);
    }
}

DefaultEventLoopGroup

Ao adicionar um ChannelHandler ao pipline, um novo grupo de threads pode ser fornecido e o negócio do Handler será executado neste thread.
DefaultEventLoopGroup pode ser útil ao adicionar ChannelHandler para executar negócios simultâneos multiencadeados.
Se DefaultEventLoopGroup não estiver definido, o padrão éEventLoopGroup workerGroup = new NioEventLoopGroup();

DefaultEventLoopGroup businessGroup = new DefaultEventLoopGroup(100);
...
addLast(businessGroup, new MyNettyServerHandler())
/**
 * 读取客户端发送过来的消息
 */
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
    
    ByteBuf byteBuf = (ByteBuf) msg;
    System.out.println("收到客户信息:" + byteBuf.toString(CharsetUtil.UTF_8));
    System.out.println("客户端地址:" + ctx.channel().remoteAddress());
    System.out.println("处理线程:" + Thread.currentThread().getName());

    ctx.executor().parent().execute(()->{
    
    
        try {
    
    
            System.out.println("parent().execute Thread = " + Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(2L);
            System.out.println("parent任务执行完成1");
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    });
    ctx.executor().parent().execute(()->{
    
    
        try {
    
    
            System.out.println("parent().execute Thread = " + Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(2L);
            System.out.println("parent任务执行完成2");
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    });
    ctx.executor().parent().execute(()->{
    
    
        try {
    
    
            System.out.println("parent().execute Thread = " + Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(2L);
            System.out.println("parent任务执行完成3");
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    });
}

O log de execução do código acima é o seguinte:

收到客户信息:Hello 服务端
客户端地址:/127.0.0.1:60345
处理线程:defaultEventLoopGroup-4-1
parent().execute Thread = defaultEventLoopGroup-4-2
parent().execute Thread = defaultEventLoopGroup-4-3
程序继续~~ defaultEventLoopGroup-4-1
parent().execute Thread = defaultEventLoopGroup-4-4
parent任务执行完成1
parent任务执行完成3
parent任务执行完成2

Tarefa cronometrada EventLoop

ctx.channel().eventLoop().schedule()Tarefas cronometradas podem ser adicionadas por meio de métodos no Handler

ctx.channel().eventLoop().schedule(()->{
    
    
    try {
    
    
        System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName());
        TimeUnit.SECONDS.sleep(2L);
        System.out.println("定时任务执行完成");
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
},10L,TimeUnit.SECONDS);

Acho que você gosta

Origin blog.csdn.net/wlddhj/article/details/129185742
Recomendado
Clasificación