Netty common core class description

MessageToByteEncoder

MessageToByteEncoder is an abstract encoder, and subclasses can override the encode method to encode objects into ByteBuf output.

MessageToByteEncoder inherits from ChannelOutboundHandlerAdapter, encode is called when outbound.

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 is a ChannelInboundHandler, which can be called a decoder, and is responsible for converting byte stream (ByteBuf) into a Message. Message is a Java object that the application can define itself.

ByteToMessageDecoder: Used to convert bytes to messages, it is necessary to check whether there are enough bytes in the 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: Inherited from ByteToMessageDecoder, there is no need to check whether there are enough bytes in the buffer, but ReplayingDecoder is slightly slower than ByteToMessageDecoder, and not all ByteBufs support it.

Use ReplayingDecoder if the project complexity is high, otherwise 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

Used to encode from one message to another, such as from POJO to POJO, is a ChannelOutboundHandler

MessageToMessageDecoder

Decoding from one message to another, such as POJO to POJO, is a ChannelInboundHandler

MessageToMessageCodec

Integrated MessageToMessageEncoder and MessageToMessageDecoder

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 is a special ChannelInboundHandler that can initialize the Channel in a simple way (calling the initChannel method).

Usually set ChannelPipeline for Channel in Bootstrap.handler(ChannelHandler), andServerBootstrap.handler(ChannelHandler) .ServerBootstrap.childHandler(ChannelHandler)

Note: When initChannel is executed, the current handler will be removed from the 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 inherits from ChannelInboundHandlerAdapter, and can specify the message type through generics.
To process incoming data we only need to implement the channelRead0 method.
SimpleChannelInboundHandler will automatically release the Bytebuffer resource occupied by the data after receiving the data, while ChannelInboundHandlerAdapter will not automatically release it.

public class MyClientHandler extends SimpleChannelInboundHandler<MessagePO> {
    
    

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

DefaultEventLoopGroup

When adding a ChannelHandler to the pipline, a new thread group can be provided, and the Handler business will be executed in this thread.
DefaultEventLoopGroup can come in handy when adding ChannelHandler to perform multi-threaded concurrent business.
If DefaultEventLoopGroup is not set, the default isEventLoopGroup 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();
        }
    });
}

The above code execution log is as follows:

收到客户信息: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

EventLoop timed task

ctx.channel().eventLoop().schedule()Timed tasks can be added through methods in 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);

Guess you like

Origin blog.csdn.net/wlddhj/article/details/129185742