1、講解內容如下
- 通過一個Echo服務講解DelimiterBasedFrameDecoder應用
- 通過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
大家加油!