未调用 Netty 编码器
Netty Encoder Not Being Called
使用 Netty 4.0.27 & Java 1.8.0_20
所以我试图通过构建一个简单的聊天服务器(我猜是典型的网络教程程序?)来了解 Netty 的工作原理。设计我自己的简单协议,称为 ARC(Andrew 的中继聊天)...所以这就是为什么您在代码中经常看到 ARC。 K,问题来了。
所以我在这里启动服务器并注册各种处理程序...
public void start()
{
System.out.println("Registering handlers...");
ArcServerInboundHandler inboundHandler = new ArcServerInboundHandler(this);
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try
{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
public void initChannel(SocketChannel ch) throws Exception
{
ch.pipeline().addLast(new ArcDecoder(), inboundHandler);
ch.pipeline().addLast(new ArcEncoder());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
try
{
System.out.println("Starting Arc Server on port " + port);
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
finally
{
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
我的 "inboundHandler" 确实 在用户连接时被调用。
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
System.out.println("CLIENT CONNECTED"); // THIS PRINTS, REACHES THIS POINT
ArcPacket packet = new ArcPacket();
packet.setArc("PUBLIC_KEY");
packet.setField("KEY", Crypto.bytesToHex(server.getRsaKeys().getPublic().getEncoded()));
ctx.writeAndFlush(packet);
}
这是我的编码器,似乎根本没有被调用...
public class ArcEncoder extends MessageToByteEncoder<ArcPacket>
{
@Override
protected void encode(ChannelHandlerContext ctx, ArcPacket msg, ByteBuf out) throws Exception
{
System.out.println("ENCODE"); // NEVER GETS HERE
String message = ArcPacketFactory.encode(msg);
byte[] data = message.getBytes("UTF-8");
out.writeBytes(data);
System.out.println("WROTE");
}
@Override
public boolean acceptOutboundMessage(Object msg) throws Exception
{
System.out.println("ACCEPT OUTBOUND MESSAGE"); // NEVER GETS HERE
return msg instanceof ArcPacket;
}
}
所以,
调用ctx.writeAndFlush(packet)的代码;是 运行,但它似乎在任何时候都没有调用编码器。我错过了一些明显的东西吗?也许我错误地添加了编码器?虽然当我将它与我见过的其他示例进行比较时它看起来是正确的。
感谢您的帮助。
您的编码器 (ArcEncoder
) 位于您的入站处理程序之后。这意味着,编码器永远不会评估 ctx.*()
方法调用。要解决您的问题,您必须在入站处理程序之前移动 ArcEncoder
:
ch.pipeline().addLast(new ArcDecoder(), new ArcEncoder(), inboundHandler);
关于事件评价顺序的更多信息,请阅读the API documentation of ChannelPipeline
。
我认为问题在于您正在使用 ChannelHandlerContext 写入 Channel。这样做的目的是将消息插入到处理程序所在的管道中,然后出站。但是由于您的解码器是在管道中的编码器之前添加的,这意味着您使用解码器上下文编写的任何内容都将插入管道中编码器之后。
确保调用编码器的正确方法是调用:
ctx.channel.writeAndFlush()
使用 Netty 4.0.27 & Java 1.8.0_20
所以我试图通过构建一个简单的聊天服务器(我猜是典型的网络教程程序?)来了解 Netty 的工作原理。设计我自己的简单协议,称为 ARC(Andrew 的中继聊天)...所以这就是为什么您在代码中经常看到 ARC。 K,问题来了。
所以我在这里启动服务器并注册各种处理程序...
public void start()
{
System.out.println("Registering handlers...");
ArcServerInboundHandler inboundHandler = new ArcServerInboundHandler(this);
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try
{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
public void initChannel(SocketChannel ch) throws Exception
{
ch.pipeline().addLast(new ArcDecoder(), inboundHandler);
ch.pipeline().addLast(new ArcEncoder());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
try
{
System.out.println("Starting Arc Server on port " + port);
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
finally
{
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
我的 "inboundHandler" 确实 在用户连接时被调用。
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
System.out.println("CLIENT CONNECTED"); // THIS PRINTS, REACHES THIS POINT
ArcPacket packet = new ArcPacket();
packet.setArc("PUBLIC_KEY");
packet.setField("KEY", Crypto.bytesToHex(server.getRsaKeys().getPublic().getEncoded()));
ctx.writeAndFlush(packet);
}
这是我的编码器,似乎根本没有被调用...
public class ArcEncoder extends MessageToByteEncoder<ArcPacket>
{
@Override
protected void encode(ChannelHandlerContext ctx, ArcPacket msg, ByteBuf out) throws Exception
{
System.out.println("ENCODE"); // NEVER GETS HERE
String message = ArcPacketFactory.encode(msg);
byte[] data = message.getBytes("UTF-8");
out.writeBytes(data);
System.out.println("WROTE");
}
@Override
public boolean acceptOutboundMessage(Object msg) throws Exception
{
System.out.println("ACCEPT OUTBOUND MESSAGE"); // NEVER GETS HERE
return msg instanceof ArcPacket;
}
}
所以,
调用ctx.writeAndFlush(packet)的代码;是 运行,但它似乎在任何时候都没有调用编码器。我错过了一些明显的东西吗?也许我错误地添加了编码器?虽然当我将它与我见过的其他示例进行比较时它看起来是正确的。
感谢您的帮助。
您的编码器 (ArcEncoder
) 位于您的入站处理程序之后。这意味着,编码器永远不会评估 ctx.*()
方法调用。要解决您的问题,您必须在入站处理程序之前移动 ArcEncoder
:
ch.pipeline().addLast(new ArcDecoder(), new ArcEncoder(), inboundHandler);
关于事件评价顺序的更多信息,请阅读the API documentation of ChannelPipeline
。
我认为问题在于您正在使用 ChannelHandlerContext 写入 Channel。这样做的目的是将消息插入到处理程序所在的管道中,然后出站。但是由于您的解码器是在管道中的编码器之前添加的,这意味着您使用解码器上下文编写的任何内容都将插入管道中编码器之后。
确保调用编码器的正确方法是调用:
ctx.channel.writeAndFlush()