-
ChannelInboundHandlerAdapter--输入数据处理器
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.fireChannelRead(msg); }
接收上一个 handler 的输出,这里的
msg
就是上一个 handler 的输出。默认情况下 adapter 会通过fireChannelRead()
方法直接把上一个 handler 的输出结果传递到下一个 handler。往 pipeline 添加的第一个 handler 中的
channelRead
方法中,msg
对象其实就是ByteBuf
。服务端在接受到数据之后,应该首先要做的第一步逻辑就是把这个 ByteBuf 进行解码,然后把解码后的结果传递到下一个 handler,如:public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf requestByteBuf = (ByteBuf) msg; // 解码 Packet packet = PacketCodeC.INSTANCE.decode(requestByteBuf); // 解码后的对象传递到下一个 handler 处理 ctx.fireChannelRead(packet) }
-
ChannelOutboundHandlerAdapter--输出数据处理器
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { ctx.write(msg, promise); }
默认情况下,这个 adapter 也会把对象传递到下一个 outBound 节点,它的传播顺序与 inboundHandler 相反
-
ByteToMessageDecoder--输入数据转换处理器
public class PacketDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { String msg=in.toString(Charset.forName("utf-8")); //在out中增加了对象,但是却没有读in时,避免出现异常:PacketDecoder.decode() did not read anything but decoded a message in.skipBytes(in.readableBytes()); //通过往这个 List 里面添加解码后的结果对象,就可以自动实现结果往下一个 handler 进行传递 //Netty 会自动进行内存的释放 out.add(msg); } }
通过往这个 List 里面添加解码后的结果对象,就可以自动实现结果往下一个 handler 进行传递
并且Netty 会自动进行ByteBuf内存的释放public class MyServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("收到消息:"+msg.toString()); } }
public class NettyServer { public static void main(String[] args) { EventLoopGroup bossGroup=new NioEventLoopGroup(); EventLoopGroup workerGroup=new NioEventLoopGroup(); ServerBootstrap bootstrap=new ServerBootstrap() .group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ch.pipeline().addLast(new PacketDecoderHanderl()); ch.pipeline().addLast(new MyServerHandler()); } }); ChannelFuture channelFuture = bootstrap.bind(9999); channelFuture.addListener(future -> { if(future.isSuccess()){ System.out.println("成功"); }else { System.out.println("失败"); } }); } }
-
MessageToByteEncoder--输出数据转换处理器
1 登录成功后直接向通道中写入java对象
public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginRequestEntity> { @Override protected void channelRead0(ChannelHandlerContext ctx, LoginRequestEntity msg) throws Exception { //登录逻辑 System.out.println("登录信息="+msg); //直接写入java对象:LoginResponseEntity ctx.channel().writeAndFlush(new LoginResponseEntity(msg.getUsername(),msg.getPassword())); } }
2 Netty会根据写入的java对象的类型和MessageToByteEncoder处理器的泛型进行匹配,在处理器中把java对象转为二进制写入到缓存就可以了。MessageToByteEncoder处理器只会关心泛型类的输出,所以如果输出的java对象没有相对应的输出处理器,者不会有任何输出。
public class LoginResponseHandler extends MessageToByteEncoder<LoginResponseEntity> { @Override protected void encode(ChannelHandlerContext ctx, LoginResponseEntity msg, ByteBuf out) throws Exception { String m="欢迎登录:"+msg.getUsername(); //把java对象转为二进制写入到缓存 out.writeBytes(m.getBytes()); } }
3 配置处理器
//解析传来的数据为实体 ch.pipeline().addLast(new PacketDecoderHanderl()); //登录处理器 ch.pipeline().addLast(new LoginRequestHandler()); //登录响应处理器 ch.pipeline().addLast(new LoginResponseHandler());
-
SimpleChannelInboundHandler--去掉if else语句
public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginEntity> { @Override protected void channelRead0(ChannelHandlerContext ctx, LoginEntity msg) throws Exception { //登录逻辑 System.out.println("登录信息="+msg); ByteBuf buffer = ctx.alloc().ioBuffer(); buffer.writeBytes("登录成功".getBytes()); ctx.writeAndFlush(buffer); } }
ByteToMessageDecoder解码后会把解码后的信息类型传给处理器,通过SimpleChannelInboundHandler的范型类,就可以达到自动选择hander处理器,实现省略if elsse语句的目的。(注意,ByteToMessageDecoder处理器一定要配置在SimpleChannelInboundHandler的前面)
//解析传来的数据为实体 ch.pipeline().addLast(new PacketDecoderHanderl()); //登录处理器 ch.pipeline().addLast(new LoginRequestHandler()); //处理String的处理器 ch.pipeline().addLast(new MyServerHandler()); ... ...
一次请求和响应的处理器调用示例图