我已经实现了使用Java编写的客户端的netty服务器。问题是我有管道的配置问题,因为我有以下消息:"到达管道的尾部。请检查您的管道配置。我已经尝试了其他相同类型的问题的答案,但不起作用。您知道如何解决问题吗?这是我对服务器的初始化:
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public NettyServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(
new StringEncoder(CharsetUtil.UTF_8),
new LineBasedFrameDecoder(8192),
new StringDecoder(CharsetUtil.UTF_8),
new ChunkedWriteHandler(),
new NettyServerHandler());
p.addLast(new HttpRequestDecoder());
p.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression.
p.addLast(new HttpContentCompressor());
p.addLast( "http-aggregator", new HttpObjectAggregator( 1024 ) );
}
}
和我的服务器代码:
public static void main(String... args) {
try {
new NettyServer().start();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("API started on port {}", PORT);
}
} catch (final Exception e) {
LOGGER.error("Unable to start API server", e);
}
}
static final boolean SSL = System.getProperty("ssl") != null;
// Use the same default port with the telnet example so that we can use the telnet client example to access it.
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8080"));
public void start() throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
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 NettyServerInitializer(sslCtx) {
});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
// f.channel().closeFuture().sync();
/* } finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}*/
}
问题是管道中的这些处理程序:
new StringEncoder(CharsetUtil.UTF_8),
new LineBasedFrameDecoder(8192),
new StringDecoder(CharsetUtil.UTF_8),
LineBasedFrameDecoder
和StringDecoder
的存在意味着传入的ByteBufs
将被解码为字符串,每行一个字符串。但是HttpRequestDecoder
希望看到ByteBufs
而不是字符串,因此传入的行将被忽略,然后它们到达打印出警告消息的管道尾部。
也不需要StringEncoder
,因为HttpResponseEncoder
已经发出ByteBufs
,如果存在,可以由SslHandler
传输或加密。
我发现了问题。这个来自方法的不良使用pipeline.addLast(...)
。处理程序在队列中使用,队列必须由服务器的处理程序结束。
它不是:
p.addLast(
new ChunkedWriteHandler(),
new NettyServerHandler());
p.addLast(new HttpRequestDecoder());
p.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression.
p.addLast(new HttpContentCompressor());
但:
p.addLast(new ChunkedWriteHandler())
p.addLast(new HttpRequestDecoder());
p.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression.
p.addLast(new HttpContentCompressor());
p.addLast(new NettyServerHandler());