为什么channelRead()没有给我发送给服务器的完整信息?当消息超过140字节(粗略地,有时更多,有时更少)时,有时会发生碎片。我使用NioServerSocketChannel类使用TCP套接字。
我使用4.1.0.Beta5。
当它到达时,是否有办法阅读完整的信息?
this.serverBootstrap = new ServerBootstrap();
this.serverBootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup(6))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
public void initChannel(SocketChannel ch) throws Exception
{
ch.pipeline().addLast(new TestServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, (int)Short.MAX_VALUE)
.option(ChannelOption.SO_RCVBUF, (int) Short.MAX_VALUE)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true);
this.serverBootstrap.bind(this.host, this.port);
类TestServerHandler扩展了ChannelInboundHandlerAdapter:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
String s = buffer.toString(CharsetUtil.UTF_8);
for(int i = 0; i < 20; i++)
{
s = s.replace("[" + ((char)i) + "]", i + "");
}
System.out.println(s.length() + "");
System.out.println();
System.out.println();
System.out.println(s);
}
我需要一种方法来获取完整的bytebuf / bytearray,当它完全到达服务器并得到通知,这样我的应用程序就可以根据客户端发送的数据以正确的方式响应。
简而言之:我如何防止碎片并让channelRead事件输出整个消息/ bytebuf。
答案 0 :(得分:5)
Netty使用的基本数据类型是Channel Buffers或ByteBuf。这只是一个字节集合而已。在您的代码中,您只需使用自定义处理程序来处理原始传入数据。这通常不是一个好习惯。一个非常基本的netty管道应该类似于以下
因此,管道由解码器/编码器组成,然后我们有自定义处理程序或日志处理程序。我们从未真正处理任何原始数据。 TCP是一种流协议。它不会识别特定数据包何时结束并且新数据包开始。即使我们发送一个非常大的数据包或说两个单独的数据包,它们也只会被视为一组字节,当我们尝试读取原始字节集时,可能会发生碎片。
正确实现一个由字符串解码器/编码器(无论你需要什么)组成的通道管道,这个问题就会消失。
答案 1 :(得分:1)
TCP提供了一个字节流,因此您不能依赖于在一个数据包中接收完整的消息。您需要一个管道中的处理程序,它知道您的消息是如何构建的。 Netty提供了一些内置处理程序,您可以根据协议进行调整。请参阅Netty用户指南中的Dealing with a Stream-based Transport。