Netty TCP 半包处理 (粘包、拆包) 示例:C/S 结构网络程序
以下是一个使用 Netty 框架处理 TCP 半包问题的示例代码,它演示了一个简单的 C/S 结构网络程序,展示了如何使用 LengthFieldBasedFrameDecoder 和 LengthFieldPrepender 解决粘包和拆包问题。
服务端代码
public class Server {
public static void main(String[] args) throws Exception {
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 LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
ch.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture f = bootstrap.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
try {
int length = buf.readInt();
byte[] content = new byte[length];
buf.readBytes(content);
String message = new String(content, CharsetUtil.UTF_8);
System.out.println('Received message: ' + message);
ctx.writeAndFlush(Unpooled.copiedBuffer(('Server received: ' + message).getBytes()));
} finally {
buf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端代码
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LengthFieldPrepender(4));
ch.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture f = bootstrap.connect('localhost', 8888).sync();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
ByteBuf buf = Unpooled.copiedBuffer(message.getBytes());
f.channel().writeAndFlush(buf);
}
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
try {
int length = buf.readInt();
byte[] content = new byte[length];
buf.readBytes(content);
String message = new String(content, CharsetUtil.UTF_8);
System.out.println('Received message: ' + message);
} finally {
buf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
运行结果
启动服务端后,客户端连接上来后可以输入任意字符串,服务端会将收到的字符串打印出来,并回复一个消息。例如:
Client: hello
Server: Received message: hello
Client: world
Server: Received message: world
解释
LengthFieldBasedFrameDecoder:用于解码接收到的数据,根据数据包头部长度信息,将粘包的数据分割成多个独立的包。LengthFieldPrepender:用于在发送数据之前添加长度信息,方便服务端解码。
通过以上代码示例,我们可以看到使用 Netty 框架处理 TCP 半包问题非常简单,只需添加相应的解码器和编码器即可。
原文地址: https://www.cveoy.top/t/topic/j56E 著作权归作者所有。请勿转载和采集!