使用Netty框架实现一个简单的CS结构的网络程序处理tcp半包问题粘包、拆包
以下是一个使用Netty框架实现的简单C/S结构的网络程序,处理了TCP半包问题(粘包、拆包):
服务端代码:
public class Server {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.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 {
String request = (String) msg;
System.out.println("Server received: " + request);
String response = "Hello, " + request + "!";
ctx.writeAndFlush(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端代码:
public class Client {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture f = b.connect("localhost", 8888).sync();
f.channel().writeAndFlush("world");
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String response = (String) msg;
System.out.println("Client received: " + response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
在服务端和客户端的ChannelPipeline中添加了LengthFieldBasedFrameDecoder和LengthFieldPrepender,用于处理TCP半包问题。LengthFieldBasedFrameDecoder可以根据长度字段自动处理粘包和拆包,而LengthFieldPrepender则在消息前添加长度字段,以便服务端正确解析消息。
在服务端的ServerHandler中,将客户端发送的消息打印出来,并回复一个Hello消息。在客户端的ClientHandler中,将服务端回复的消息打印出来。
运行客户端和服务端程序,可以看到客户端发送的消息被服务端正确接收并回复了一个Hello消息
原文地址: https://www.cveoy.top/t/topic/cFxd 著作权归作者所有。请勿转载和采集!