NettyLongToByteEncoder:
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class NettyLongToByteEncoder extends MessageToByteEncoder<Long> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Long aLong, ByteBuf byteBuf) throws Exception {
System.out.println("NettyLongToByteEncoder encode 被调用");
System.out.println("msg = " + aLong);
byteBuf.writeLong(aLong);
}
}
NettyByteToLongDecoder:
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class NettyByteToLongDecoder extends ByteToMessageDecoder {
/**
* abcdabcdabcdabcd 会根据接收到的数据,被调用多次, 知道确定没有新的元素被添加到list 或者 ByteBuf 没有更多的可读字节为止
* 如果 list 的不为空,就会将 list 的内容传递给下一个 channelInboundhandler处理,该处理器的方法也会被调用多次
* @param channelHandlerContext 上下文对象
* @param byteBuf 入站的 byteBuf
* @param list 将解码后的数据传递给下一个 handler
* @throws Exception
*/
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
System.out.println("NettyByteToLongDecoder 被调用");
// 因为 Long 8个字节
if (byteBuf.readableBytes() >= 8) {
list.add(byteBuf.readLong());
}
}
}
NettyServer:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new NettyServerInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(9527).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerHandler:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class NettyServerHandler extends SimpleChannelInboundHandler<Long> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Long aLong) throws Exception {
System.out.println("从客户端" + channelHandlerContext.channel().remoteAddress() + " 读取到Long" + aLong);
// 给客户端发送一个 Long
channelHandlerContext.writeAndFlush(4396L);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
NettyServerInitializer:
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 入站的 handler 进行解码
pipeline.addLast(new NettyByteToLongDecoder());
// 出站的 handler 进行编码, 入站 和 出站 两条线进行走
pipeline.addLast(new NettyLongToByteEncoder());
// 自定义的 handler 处理业务逻辑
pipeline.addLast(new NettyServerHandler());
}
}
NettyClient:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class).handler(new NettyClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 9527).sync();
channelFuture.channel().closeFuture().sync();
}finally {
group.shutdownGracefully();
}
}
}
NettyClientHandler:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class NettyClientHandler extends SimpleChannelInboundHandler<Long> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Long aLong) throws Exception {
System.out.println("服务器的ip=" + channelHandlerContext.channel().remoteAddress());
System.out.println("收到服务器消息=" + aLong);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyClientHandler 发送数据");
ctx.writeAndFlush(9527L);
/**
* abcdabcdabcd 16个字节
* 该处理器的前一个 handler 是 NettyLongToByteEncoder
* NettyLongToByteEncoder 的父类是 MessageToByteEncoder
* 在编写 encoder 时, 要注意传入的数据类型和处理的数据类型一致
*/
//ctx.writeAndFlush(Unpooled.copiedBuffer("abcdabcdabcdabcd", CharsetUtil.UTF_8));
}
}
NettyClientInitializer:
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 加入一个 出站的 handler 对数据进行编码
pipeline.addLast(new NettyLongToByteEncoder());
// 这是一个入站的解码器(handler)
pipeline.addLast(new NettyByteToLongDecoder());
// 加入一个自定义的 handler, 处理业务逻辑
pipeline.addLast(new NettyClientHandler());
}
}
MessageToByteEncoder 的 write 方法:
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ByteBuf buf = null;
try {
if (this.acceptOutboundMessage(msg)) { // 判断当前 msg, 是不是该处理的类型
I cast = msg;
buf = this.allocateBuffer(ctx, msg, this.preferDirect);
try {
this.encode(ctx, cast, buf);
} finally {
ReferenceCountUtil.release(msg);
}
if (buf.isReadable()) {
ctx.write(buf, promise);
} else {
buf.release();
ctx.write(Unpooled.EMPTY_BUFFER, promise);
}
buf = null;
} else { // 直接发送
ctx.write(msg, promise);
}
} catch (EncoderException var17) {
throw var17;
} catch (Throwable var18) {
throw new EncoderException(var18);
} finally {
if (buf != null) {
buf.release();
}
}
}
结论:
- 不论解码器 handler 还是 编码器 handler 即接收的消息类型必须与待处理消息类型一致,否则该 handler 不会被执行
- 在解码器 进行数据解码时,需要判断缓存区(ByteBuf)的数据是否足够,否则接收到的结果会与期望结果可能不一致