netty handler解码、编码的顺序

今天来说说netty,给bootstrap注入 handler时,解码,编码的触发顺序。

首先写server

package helloNettyTest2;

import java.net.InetAddress;
import java.util.List;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class ServerTest {

	public static void main(String[] args) throws InterruptedException {
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
					.childHandler(new HelloServerInitializer());

			// 服务器绑定端口监听
			ChannelFuture f = bootstrap.bind(8080).sync();
			// 监听服务器关闭监听
			f.channel().closeFuture().sync();
			// 可以简写为
			/* b.bind(portNumber).sync().channel().closeFuture().sync(); */
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
}

class HelloServerInitializer extends ChannelInitializer<SocketChannel> {

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {

		ChannelPipeline pipeline = ch.pipeline();

		// 以("\n")为结尾分割的 解码器
		// pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192,
		// Delimiters.lineDelimiter()));
		// 字符串解码 和 编码
		// pipeline.addLast(new IdleStateHandler(5 ,0, 0, TimeUnit.SECONDS));
		pipeline.addLast("encoder", new StringEncoder());
		pipeline.addLast("decoder", new StringDecoder());
		pipeline.addLast("encoder1", new encoder1());
		pipeline.addLast("encoder2", new encoder2());
		pipeline.addLast("decoder1", new decoder1());
		pipeline.addLast("decoder2", new decoder2());

		// 自己的逻辑Handler
		pipeline.addLast("handler", new HelloServerHandler());
	}
}

class HelloServerHandler extends SimpleChannelInboundHandler<String> {

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		// 收到消息直接打印输出
		System.err.println("channelRead0");
		System.out.println(ctx.channel().remoteAddress() + " Say : " + msg);
		// 返回客户端消息 - 我已经接收到了你的消息
		ctx.writeAndFlush("Received your message !\n");
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// 收到消息直接打印输出
		System.err.println("channelRead");
		System.out.println(ctx.channel().remoteAddress() + " Say : " + msg);
		// 返回客户端消息 - 我已经接收到了你的消息
		ctx.writeAndFlush("Received your message !\n");

	}

	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");
		ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n");
		super.channelActive(ctx);
	}
}

class encoder1 extends MessageToMessageEncoder<String> {

	@Override
	protected void encode(ChannelHandlerContext paramChannelHandlerContext, String paramI, List<Object> paramList)
			throws Exception {
		// TODO Auto-generated method stub
		System.err.println("encoder1:" + paramI);
		paramList.add(paramI);
	}

}

class encoder2 extends MessageToMessageEncoder<String> {

	@Override
	protected void encode(ChannelHandlerContext paramChannelHandlerContext, String paramI, List<Object> paramList)
			throws Exception {
		// TODO Auto-generated method stub
		System.err.println("encoder2:" + paramI);
		paramList.add(paramI);
	}
}

class decoder1 extends MessageToMessageDecoder<String> {

	@Override
	protected void decode(ChannelHandlerContext paramChannelHandlerContext, String paramI, List<Object> paramList)
			throws Exception {
		System.err.println("decoder1:" + paramI);
		paramList.add(paramI);
	}

}

class decoder2 extends MessageToMessageDecoder<String> {

	@Override
	protected void decode(ChannelHandlerContext paramChannelHandlerContext, String paramI, List<Object> paramList)
			throws Exception {
		// TODO Auto-generated method stub
		System.err.println("decoder2:" + paramI);
		paramList.add(paramI);
	}
}

Chient

package helloNettyTest2;

import java.io.IOException;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class ClientTest {

	public static void main(String[] args) throws InterruptedException, IOException {

		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

		Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new HelloClientInitializer());
		// 连接服务端
		try {
			// 1.
			// Channel ch = bootstrap.connect("127.0.0.1",
			// 8080).sync().channel();
			// // 控制台输入
			// BufferedReader in = new BufferedReader(new
			// InputStreamReader(System.in));
			// for (;;) {
			// String line = in.readLine();
			// if (line == null) {
			// continue;
			// }
			// /*
			// * 向服务端发送在控制台输入的文本 并用"\r\n"结尾
			// * 之所以用\r\n结尾 是因为我们在handler中添加了 DelimiterBasedFrameDecoder 帧解码。
			// * 这个解码器是一个根据\n符号位分隔符的解码器。所以每条消息的最后必须加上\n否则无法识别和解码
			// * */
			// ch.writeAndFlush(line + "\r\n");
			// }
			// 2.
			ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();
			channelFuture.channel().writeAndFlush("Hello Netty Server ,I am a common client");
			channelFuture.channel().closeFuture().sync();

		} finally {
			// The connection is closed automatically on shutdown.
			eventLoopGroup.shutdownGracefully();
		}
	}
}

class HelloClientInitializer extends ChannelInitializer<SocketChannel> {

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		// TODO Auto-generated method stub
		/*
		 * 这个地方的 必须和服务端对应上。否则无法正常解码和编码
		 * 
		 * 解码和编码 我将会在下一张为大家详细的讲解。再次暂时不做详细的描述
		 * 
		 */
		ChannelPipeline pipeline = ch.pipeline();
		// pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192,
		// Delimiters.lineDelimiter()));
		pipeline.addLast("decoder", new StringDecoder());
		pipeline.addLast("encoder", new StringEncoder());

		// 客户端的逻辑
		pipeline.addLast("handler", new HelloClientHandler());
	}

}

class HelloClientHandler extends SimpleChannelInboundHandler<String> {

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("Client active ");
		super.channelActive(ctx);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("Client close ");
		super.channelInactive(ctx);
	}
	@Override
	protected void channelRead0(ChannelHandlerContext paramChannelHandlerContext, String msg) throws Exception {
		System.out.println("Server say : " + msg);

	}
}

class test1 extends ChannelOutboundHandlerAdapter {

}

运行 server、client 结果

netty handler解码、编码的顺序会发现解码的顺序是从上往下(StringDecoder、encoder1、encoder2) 而编码的顺序是从下往上的(decoder2、decoder1、StringDecoder)