1. 程式人生 > >netty handler解碼、編碼的順序

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 結果

會發現解碼的順序是從上往下(StringDecoder、encoder1、encoder2) 而編碼的順序是從下往上的(decoder2、decoder1、StringDecoder)