一.使用DelimiterBasedFrameDecoder自动完成以分隔符作为结束标志的解码
1.1 DelimiterBasedFrameDecoder服务端开发
1.1.1 EchoServer实现
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;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
importio.netty.handler.codec.DelimiterBasedFrameDecoder;
importio.netty.handler.codec.LineBasedFrameDecoder;
importio.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/*
* 利用DelimiterBasedFrameDecoder完成以分隔符作为码流结束的标识
*/
public class EchoServer {
publicvoid bind(int port) throws Exception{
//配置服务端的NIO线程组
EventLoopGroupbossGroup =new NioEventLoopGroup();
EventLoopGroupworkerGroup =new NioEventLoopGroup();
try{
//用于启动NIO服务器的辅助启动类,降低服务端的开发复杂度
ServerBootstrapb=new ServerBootstrap();
b.group(bossGroup,workerGroup).
channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.handler(newLoggingHandler(LogLevel.INFO))
.childHandler(newChannelInitializer<SocketChannel>() {
@Override
publicvoid initChannel(SocketChannel ch) throws Exception{
ByteBufdelimiter=Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(
newDelimiterBasedFrameDecoder(1024,delimiter)); // 单条消息最大长度:1024
ch.pipeline().addLast(newStringDecoder());
ch.pipeline().addLast(newEchoServerHandler());
}
});
//绑定端口,同步等待成功
ChannelFuturef=b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}catch (Exception e) {
//TODO: handle exception
}finally{
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
publicstatic void main(String[] args) throws Exception{
intport=8080;
if(args!=null&&args.length>0){
try{
port=Integer.valueOf(args[0]);
}catch (NumberFormatException e) {
//TODO: handle exception
}
}
newEchoServer().bind(port);
}}
1.1.2 EchoServerHandler实现
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/*
* 利用LineBasedFrameDecoder解决TCP粘包问题
*/
public classEchoServerHandler extends ChannelHandlerAdapter{
int counter =0;
@Override
public voidchannelRead(ChannelHandlerContext ctx,Object msg)throwsException{
Stringbody=(String)msg;
System.out.println("This is"+++counter+"times receive client: ["+body+"]" );
body+="$_";
ByteBufecho=Unpooled.copiedBuffer(body.getBytes());
ctx.writeAndFlush(echo);
}
@Override
public voidexceptionCaught(ChannelHandlerContext ctx,Throwable cause){
cause.printStackTrace();
ctx.close(); // 发生异常,关闭链路
}
}
1.2 DelimitedBasedFrameDecoder客户端开发
1.2.1 EchoClient实现
import client.TimeClient;
import io.netty.bootstrap.Bootstrap;
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;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioSocketChannel;
importio.netty.handler.codec.DelimiterBasedFrameDecoder;
importio.netty.handler.codec.string.StringDecoder;
public class EchoClient {
publicvoid connect(int port,String host) throws Exception{
//配置客户端NIO线程组
EventLoopGroupgroup=new NioEventLoopGroup();
try{
Bootstrapb=new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(newChannelInitializer<SocketChannel>() {
@Override
publicvoid initChannel(SocketChannel ch) throws Exception{
ByteBufdelimiter=Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(newDelimiterBasedFrameDecoder(1024,delimiter));
ch.pipeline().addLast(newStringDecoder());
ch.pipeline().addLast(newEchoClientHandler());
}
});
//发起异步连接操作
ChannelFuturef=b.connect(host,port).sync();
//等待客户端链路关闭
f.channel().closeFuture().sync();
}catch (Exception e) {
//TODO: handle exception
}finally{
//优雅退出,释放NIO线程组
group.shutdownGracefully();
}
}
publicstatic void main(String[] args) throws Exception{
intport=8080;
if(args!=null&&args.length>0){
try{
port=Integer.valueOf(args[0]);
}catch (NumberFormatException e) {
//TODO: handle exception
}
newTimeClient().connect(port,"127.0.0.1");
}
}
}
1.2.2 EchoClientHandler实现
import io.netty.buffer.Unpooled;
importio.netty.channel.ChannelHandlerAdapter;
importio.netty.channel.ChannelHandlerContext;
public class EchoClientHandler extendsChannelHandlerAdapter{
private int counter;
static final String ECHO_REQ="Welcome to Netty.$_";
public EchoClientHandler(){
}
@Override
public void channelActive(ChannelHandlerContext ctx){
for(int i=0;i<10;i++){
ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));
}
}
public void channelRead(ChannelHandlerContext ctx,Object msg) throwsException{
ctx.flush();
}
@Override
public voidexceptionCaught(ChannelHandlerContext ctx,Throwable cause){
cause.printStackTrace();
ctx.close();
}
}
二.使用FiexLengthFrameDecoder定长解码器进行自动解码
2.1 FixLengthFrameDecoder服务的开发
2.1.1 EchoServer实现
package fixedlength;
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;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioServerSocketChannel;
importio.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
importio.netty.handler.codec.LineBasedFrameDecoder;
importio.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
importio.netty.handler.logging.LoggingHandler;
/*
* 利用FixedLengthFrameDecoder固定解码长度
*/
public class EchoServer {
publicvoid bind(int port) throws Exception{
//配置服务端的NIO线程组
EventLoopGroupbossGroup =new NioEventLoopGroup();
EventLoopGroupworkerGroup =new NioEventLoopGroup();
try{
//用于启动NIO服务器的辅助启动类,降低服务端的开发复杂度
ServerBootstrapb=new ServerBootstrap();
b.group(bossGroup,workerGroup).
channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.handler(newLoggingHandler(LogLevel.INFO))
.childHandler(newChannelInitializer<SocketChannel>() {
@Override
publicvoid initChannel(SocketChannel ch) throws Exception{
ByteBufdelimiter=Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(
newFixedLengthFrameDecoder(20)); // 固定解码长度为20
ch.pipeline().addLast(newStringDecoder());
ch.pipeline().addLast(newEchoServerHandler());
}
});
//绑定端口,同步等待成功
ChannelFuturef=b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}catch (Exception e) {
//TODO: handle exception
}finally{
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
publicstatic void main(String[] args) throws Exception{
intport=8080;
if(args!=null&&args.length>0){
try{
port=Integer.valueOf(args[0]);
}catch (NumberFormatException e) {
//TODO: handle exception
}
}
newEchoServer().bind(port);
}
}
2.1.2 EchoServerHandler实现
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/*
* 打印读取的消息
*/
public classEchoServerHandler extends ChannelHandlerAdapter{
@Override
public voidchannelRead(ChannelHandlerContext ctx,Object msg)throwsException{
System.out.println("Receive client:["+msg+"]");
}
@Override
public voidexceptionCaught(ChannelHandlerContext ctx,Throwable cause){
cause.printStackTrace();
ctx.close(); // 发生异常,关闭链路
}
}
利用FixedLengthFrameDecoder解码器,无论一次接受多少数据报,它都会按照构造函数中固定长度进行解码