我正在尝试使用简单的服务器 - 客户端应用程序进入Netty(代码见下文)。
我正在努力解决两个问题:
ConfigServerHandler和。正确调用ConfigClientHandler。但是FeedbackServerHandler分别是从不调用FeedbackClientHandler。为什么?根据文档,应该一个接一个地调用处理程序。
我想要几个处理程序。这些处理程序中的每一个仅对另一方发送的一些消息感兴趣(例如,由客户端发送,由服务器接收)。
感谢您的帮助!
KJ
这就是服务器的创建方式:
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ConfigServerHandler(),
new FeedbackServerHandler());
}
});
b.bind(mPort).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
其中一个Handler类(FeedbackServerHandler完全相同但解析为Integer):
public class ConfigServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("ConfigServerHandler::channelRead, " +(String)msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
客户端看起来很相似:
public Client(String host, int port) throws InterruptedException {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ConfigClientHandler(),
new FeedbackClientHandler());
}
});
b.connect(host, port).sync().channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
这是一个客户端处理程序(另一个发送Integer消息并在'channelRead'方法中解析为Integer):
public class ConfigClientHandler extends ChannelInboundHandlerAdapter {
private final String firstMessage = "blubber";
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("ConfigClientHandler::channelActive");
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("ConfigClientHandler::channelRead, " +(String)msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
}
答案 0 :(得分:8)
您正在使用ChannelInboundHandlerAdapter
,这对您的“中间”处理程序ConfigXxxxxHandler
很好。
但您使用channelRead
方法,然后在ctx.write(msg)
内使用。 ctx.write(msg)
将首先通过前一个处理程序(ObjectDecoder
)将msg写回另一个服务器,而不是下一个处理程序(在您的情况下为FeedbackClientHandler
)。
如果要将消息发送到下一个处理程序,则应使用以下内容:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("ConfigClientHandler::channelRead, " +(String)msg);
ctx.fireChannelRead(msg);
}
当然ctx.flush()
中没有channelReadComplete
(因为不再写在那里)。
但是,在最后的FeedbackClientHandler
中,请使用ctx.write(yourNewMessage)
的flush方法或使用ctx.writeAndFlush(yourNewMessage)
。
所以要恢复:
ctx.write
会将消息发送到电汇,所以前一个处理程序发送到通道然后发送到网络,所以出站方式ctx.fireChannelRead
会将消息发送到下一个处理程序(相反方式),因此入站方式有关详细信息,请参阅http://netty.io/wiki/new-and-noteworthy-in-4.0.html#wiki-h4-16。
你或许也应该反转编码器/解码器,因为一般来说最好首先是解码器,然后是管道中的编码器。
p.addLast(
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEncoder(),
new ConfigClientHandler(),
new FeedbackClientHandler());