Netty使用LineBasedFrameDecoder解决粘包问题
问题代码:
服务:
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024).childHandler(new TimeServerHandler());
ChannelFuture channelFuture = serverBootstrap.bind(6010).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
handler:
public class TimeServerHandler extends SimpleChannelInboundHandler<Object> {
private int count;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
System.out.println(new String(bytes));
//
String str = "hello client**";
System.out.println("receive one msg.count="+ ++count);
ByteBuf whriteByteBuf = Unpooled.copiedBuffer(str.getBytes());
ctx.write(whriteByteBuf);
// super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
// super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// super.exceptionCaught(ctx, cause);
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext arg0, Object arg1) throws Exception {
}
}
客户:
public class TimeClient {
public static void main(String[] args) throws Exception {
int port = 6010;
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup).channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("localhost",port).sync();
channelFuture.channel().closeFuture().sync();
}finally {
workGroup.shutdownGracefully();
}
}
}
handler:
public class TimeClientHandler extends SimpleChannelInboundHandler<Object> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String msg = "hello server";
for(int i = 0; i < 100; i++){
//注意这里每次byteBuf都要重新生成。
ByteBuf byteBuf = Unpooled.buffer(msg.length());
byteBuf.writeBytes(msg.getBytes());
ctx.writeAndFlush(byteBuf);
}
// super.channelActive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
System.out.println(new String(bytes)+"client888");
// super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext arg0, Object arg1) throws Exception {
}
}
服务端运行:
客户端运行:
看到服务端只收到了27条客户端传递过来的数据,应该是有100条才对,可以看出此处发生了TCP粘包。
接下来使用Netty里的LineBasedFrameDecoder来解决此问题。
同样新的服务端:
public class TimeServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(new TimeServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(7601).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
新的客户端:
public class TimeClient {
public static void main(String[] args) throws Exception {
int port = 7601;
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup).channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});//这里就是用ChannelInitializer来处理的。
ChannelFuture channelFuture = bootstrap.connect("localhost",port).sync();
channelFuture.channel().closeFuture().sync();
}finally {
workGroup.shutdownGracefully();
}
}
}
两者的Handler类代码不变。 服务端输出:
客户端输出:
发现TCP粘包问题已经解决。