public class ServerBytesFramerDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
而如果直接继承ReplayingDecoder类,decode() 函数的实现会类似下面的形式:
public class ServerBytesFramerDecoder extends ReplayingDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
public abstract class ReplayingDecoder extends ByteToMessageDecoder {
static final Signal REPLAY = Signal.valueOf(ReplayingDecoder.class, "REPLAY");
private final ReplayingDecoderByteBuf replayable = new ReplayingDecoderByteBuf();
private S state;
private int checkpoint = -1;
final class ReplayingDecoderByteBuf extends ByteBuf {
private static final Signal REPLAY = ReplayingDecoder.REPLAY;
private ByteBuf buffer;
private boolean terminated;
private SwappedByteBuf swapped;
public final class Signal extends Error implements Constant {
private static final long serialVersionUID = -221145131122459977L;
@Override
public byte[] array() {
throw new UnsupportedOperationException();
}
@Override
public int arrayOffset() {
throw new UnsupportedOperationException();
}
本示例的验证场景:
在这个示例中,客户端发送了12个字节的数据,服务端的ServerBytesFramerDecoder解析成功,传递给了后续的ServerRegisterRequestHandler。
package com.thb.power.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* 服务端的主函数
* @author thb
*
*/
public class MainStation {
static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));
public static void main(String[] args) throws Exception {
// 配置服务器
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new MainStationInitializer());
// 启动服务端
ChannelFuture f = b.bind(PORT).sync();
// 等待直到server socket关闭
f.channel().closeFuture().sync();
} finally {
// 关闭所有event loops以便终止所有的线程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.thb.power.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class MainStationInitializer extends ChannelInitializer {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new ServerBytesFramerDecoder());
p.addLast(new ServerRegisterRequestHandler());
}
}
package com.thb.power.server;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
package com.thb.power.server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerRegisterRequestHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf m = (ByteBuf)msg;
System.out.println("ServerRegisterRequestHandler: readableBytes: " + m.readableBytes());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
从上面服务端的输出可以看出,ServerRegisterRequestHandler收到了12个字节的数据。而ServerRegisterRequestHandler在ServerBytesFramerDecoder的后面,所以这12个字节的数据是ServerBytesFramerDecoder解析出来传递过来的。当时在ChannelPipeline添加的ChannelHandler的顺序:
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new ServerBytesFramerDecoder());
p.addLast(new ServerRegisterRequestHandler());
}
本示例的验证场景:
在这个示例中,客户端发送了12个字节的数据,服务端的ServerBytesFramerDecoder要求接收100个字节的数据,所以没有接收到足够的数据,导致后续的ServerRegisterRequestHandler没有接收到数据。
package com.thb.power.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* 服务端的主函数
* @author thb
*
*/
public class MainStation {
static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));
public static void main(String[] args) throws Exception {
// 配置服务器
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new MainStationInitializer());
// 启动服务端
ChannelFuture f = b.bind(PORT).sync();
// 等待直到server socket关闭
f.channel().closeFuture().sync();
} finally {
// 关闭所有event loops以便终止所有的线程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.thb.power.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class MainStationInitializer extends ChannelInitializer {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new ServerBytesFramerDecoder());
p.addLast(new ServerRegisterRequestHandler());
}
}
package com.thb.power.server;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
package com.thb.power.server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerRegisterRequestHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf m = (ByteBuf)msg;
System.out.println("ServerRegisterRequestHandler: readableBytes: " + m.readableBytes());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
从上面服务端的输出可以发现,LoggingHandler是收到了12个字节的数据,但ServerRegisterRequestHandler没有接收到数据。这是因为ServerBytesFramerDecoder没有接收到足够的数据(期望接收100个字节),也就没有传递给后续的ServerRegisterRequestHandler。
本示例的验证场景:
在这个示例中,客户端发送了12个字节的数据,服务端的解码器ServerBytesFramerDecoder通过调用checkpoint(S state)来更新解码器的状态,读取数据中的不同的部分。读到期望的内容,传递给后续的ServerRegisterRequestHandler。
这个场景用到了ReplayingDecoder的几个函数,先解释下:
package com.thb.power.server;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* 服务端的主函数
* @author thb
*
*/
public class MainStation {
private static final Logger logger = LogManager.getLogger();
static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));
public static void main(String[] args) throws Exception {
logger.traceEntry();
// 配置服务器
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new MainStationInitializer());
// 启动服务端
ChannelFuture f = b.bind(PORT).sync();
// 等待直到server socket关闭
f.channel().closeFuture().sync();
} finally {
// 关闭所有event loops以便终止所有的线程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
logger.traceExit();
}
}
package com.thb.power.server;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.thb.power.server.register.ServerRegisterRequestHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class MainStationInitializer extends ChannelInitializer {
private static final Logger logger = LogManager.getLogger();
@Override
public void initChannel(SocketChannel ch) throws Exception {
logger.traceEntry();
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new ServerBytesFramerDecoder());
p.addLast(new ServerRegisterRequestHandler());
logger.traceExit();
}
}
package com.thb.power.server;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
private static final Logger logger = LogManager.getLogger();
private byte length;
public ServerBytesFramerDecoder() {
super(ServerBytesFramerDecoderState.READ_START_MARK);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
package com.thb.power.server;
public enum ServerBytesFramerDecoderState {
READ_START_MARK,
READ_FUNCTION_CODE,
READ_LENGTH,
READ_CONTENT;
}
package com.thb.power.server.register;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerRegisterRequestHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
logger.traceEntry();
ByteBuf m = (ByteBuf)msg;
logger.info("readableBytes: " + m.readableBytes());
logger.traceExit();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
从服务端的输出可以看出,ServerRegisterRequestHandler成功接收到了9个字节的数据。
为什么是接收到9个字节的数据呢?
因为在ServerBytesFramerDecoder的decode函数中,读取第1个字节的协议开始符、1个字节的功能码、1个字节的长度字段,这3个字节只是读出来,并没有向后传递。所以12个字节的数据,减去3个字节的数据,向后传递的是9个字节的数据。
此处只是为了说明checkpoint(S state)的场景,真正的业务中,要结合业务实际情况处理,例如判断功能码等。
这个对比的场景:
为了进行对比,只列出ServerBytesFramerDecoder类的代码,其它类的代码没有改动。
package com.thb.power.server;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
private static final Logger logger = LogManager.getLogger();
private byte length;
public ServerBytesFramerDecoder() {
super(ServerBytesFramerDecoderState.READ_START_MARK);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
启动服务端,启动客户端并发送12个字节的数据给服务端,观察服务端的输出:
从服务端输出可以看出,只进入decode函数一次,就把报文的几个状态都处理完了,将读出的数据传递给了后面的ServerRegisterRequestHandler。为什么传递给后面ServerRegisterRequestHandler是9个字节的数据,上面有解释。
package com.thb.power.server;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
private static final Logger logger = LogManager.getLogger();
private byte length;
public ServerBytesFramerDecoder() {
super(ServerBytesFramerDecoderState.READ_START_MARK);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
启动服务端,启动客户端并发送12个字节的数据给服务端,观察服务端的输出:
从服务端输出可以看出,因为switch语句块每个case处理完一个状态就break了,所以4个状态就进入decode函数4次,每个状态进入一次。
只给出ReplayingDecoder的实现类ServerBytesFramerDecoder的decode函数的代码片段,其它的省略:
package com.thb.power.server;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
public class ServerBytesFramerDecoder extends ReplayingDecoder {
private static final Logger logger = LogManager.getLogger();
private byte length;
......省略其它代码
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List
输出:
从输出可以看出,实现类是io.netty.handler.codec.ReplayingDecoderByteBuf