Netty4.x分隔符和定長解碼器應用

1、講解內容如下

  1. 通過一個Echo服務講解DelimiterBasedFrameDecoder應用
  2. 通過telnet調試FixedLengthFrameDecoder的應用

2、DelimiterBasedFrameDecoder應用開發

EchoServer.java


package com.moreday.netty.fixed;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @ClassName EchoServer
 * @Description TODO(Echo簡單的輸出服務,熟悉Delimiter的應用)
 * @author 尋找手藝人
 * @Date 2020年4月10日 下午5:22:45
 * @version 1.0.0
 */
public class EchoServer {

	public void bind(int port) throws Exception {
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup worker = new NioEventLoopGroup();

		try {

			ServerBootstrap b = new ServerBootstrap();
			b.group(boss, worker).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
					.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							//創建分隔符緩存對象ByteBuf,並使用#號作爲分隔符
							ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());
							//創建DelimiterBasedFrameDecoder對象並將其加入到pipeline中
							//第一個參數:1024參數,代表單條消息的最大長度
							//第二個參數:分隔符緩衝對象
							ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
							ch.pipeline().addLast(new StringDecoder());
							ch.pipeline().addLast(new EchoServerHandler());
						}
					});
            //綁定端口同步等待成功
			ChannelFuture f = b.bind(port).sync();
			//等待服務端監聽端口關閉
			f.channel().closeFuture().sync();
		} finally {
			boss.shutdownGracefully();
			worker.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) throws Exception {
		int port = 8080;
		if(args!=null && args.length>0) {
			port = Integer.valueOf(args[0]);
		}
		new EchoServer().bind(port);
	}

}

EchoServerHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @ClassName EchoServerHandler
 * @Description TODO(這裏用一句話描述這個類的作用)
 * @author 尋找手藝人
 * @Date 2020年4月10日 下午6:33:53
 * @version 1.0.0
 */
public class EchoServerHandler extends SimpleChannelInboundHandler<String> {

	private int counter = 0;

	/*
	 * (非 Javadoc) Description:
	 * 
	 * @see
	 * io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.
	 * ChannelHandlerContext, java.lang.Object)
	 */
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		// TODO Auto-generated method stub
		String body = msg;
		System.out.println("This is counter " + ++counter + " times receive client:[" + body + "]");
		//我愛你CN
		body += "=>I Love China" + "#";
		ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
		ctx.writeAndFlush(echo);
	}
}

客戶端
EchoClient.java

import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * @ClassName EchoClient
 * @Description TODO(這裏用一句話描述這個類的作用)
 * @author 尋找手藝人
 * @Date 2020年4月10日 下午6:48:04
 * @version 1.0.0
 */
public class EchoClient {
	
	public void connect(int port,String host) throws Exception {
		//配置客戶端NIO線程
	     EventLoopGroup group = new NioEventLoopGroup();
	     try {
	    	 Bootstrap b = new Bootstrap();
             b.group(group)
             .channel(NioSocketChannel.class)
             .option(ChannelOption.TCP_NODELAY,true)
             .handler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					//創建分隔符緩存對象ByteBuf,並使用#號作爲分隔符
					ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());
					//創建DelimiterBasedFrameDecoder對象並將其加入到pipeline中
					//第一個參數:1024參數,代表單條消息的最大長度
					//第二個參數:分隔符緩衝對象
					ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
					ch.pipeline().addLast(new StringDecoder());
					ch.pipeline().addLast(new EchoClientHandler());
					
				}
			});
            //發起異步鏈接操作
             ChannelFuture f = b.connect(host, port).sync();
             
             //等待客戶端鏈路關閉
             f.channel().closeFuture().sync();
		} finally {
			// TODO: handle finally clause
			group.shutdownGracefully();
		}
	}
	
	
	public static void main(String[] args) throws Exception {
		int port = 8080;
		if(args!=null && args.length>0) {
			port = Integer.valueOf(args[0]);
		}
		new EchoClient().connect(port, "127.0.0.1");
	}
	
     
}

EchoClientHandler.java

package com.moreday.netty.fixed;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @ClassName EchoClientHandler
 * @Description TODO(這裏用一句話描述這個類的作用)
 * @author 尋找手藝人
 * @Date 2020年4月10日 下午6:54:16
 * @version 1.0.0
 */
public class EchoClientHandler  extends SimpleChannelInboundHandler<String>{

	
	private int counter = 0;
	static final String ECHO_REQ = "HI, Welcome to Netty4.x"+"#";
	
	/**
	 * @Description TODO(這裏用一句話描述這個方法的作用)
	 */
	public EchoClientHandler() {
		// TODO Auto-generated constructor stub
	}
	
	/* (非 Javadoc)
	 * Description:
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++) {
			ByteBuf msg = Unpooled.copiedBuffer(ECHO_REQ.getBytes());
			ctx.writeAndFlush(msg);
		}
	}
	/* (非 Javadoc)
	 * Description:
	 * @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 */
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("This is counter "+ ++counter+" times receive server +["+msg+"]");
	}

}

分別啓動服務端與客戶端,運行結果如下所示:
在這裏插入圖片描述

3、FixedLengthFrameDecoder開發

package com.moreday.netty.fixed;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @ClassName EchoServer
 * @Description TODO(Echo簡單的輸出服務,熟悉Delimiter的應用)
 * @author 尋找手藝人
 * @Date 2020年4月10日 下午5:22:45
 * @version 1.0.0
 */
public class EchoFixedServer {

	public void bind(int port) throws Exception {
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup worker = new NioEventLoopGroup();

		try {

			ServerBootstrap b = new ServerBootstrap();
			b.group(boss, worker).channel(NioServerSocketChannel.class)
			.option(ChannelOption.SO_BACKLOG, 100)
			.handler(new LoggingHandler(LogLevel.INFO))
			.childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							//創建FixedLengthFrameDecoder對象並將其加入到pipeline中
							ch.pipeline().addLast(new FixedLengthFrameDecoder(10));
							ch.pipeline().addLast(new StringDecoder());
							ch.pipeline().addLast(new EchoServerHandler());
						}
					});
            //綁定端口同步等待成功
			ChannelFuture f = b.bind(port).sync();
			//等待服務端監聽端口關閉
			f.channel().closeFuture().sync();
		} finally {
			boss.shutdownGracefully();
			worker.shutdownGracefully();
		}
	}
	
	public static void main(String[] args) throws Exception {
		int port = 8080;
		if(args!=null && args.length>0) {
			port = Integer.valueOf(args[0]);
		}
		new EchoFixedServer().bind(port);
	}

}

啓動服務端
啓動telnet鏈接服務端
在這裏插入圖片描述
在這裏插入圖片描述
telnet客戶端窗口輸入hi i love china
在這裏插入圖片描述
看後臺服務端只輸出10個字符,完全符合我們定長FixedLengthFrameDecoder(10)設想
在這裏插入圖片描述


到此,Netty4.x分隔符和定長解碼器應用講解完成!

迄今爲止的所有例子使用 ByteBuf 作爲協議消息的主要數據結構。在下篇博文中,我們介紹一下如何使用 POJO 代ByteBuf
大家加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章