💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 一、粘包拆包问题的解决方案,有三种方案 1.消息固定长度,如果消息没有达到固定为大小,用空格补位 2.在包尾部添加特殊字符进行分割,回车 3消息=头+体,头包含消息的长度 如果想要了解什么是tcp粘包和拆包的问题 可以看这篇博客 我认为写的还可以:https://blog.csdn.net/hbtj_1216/article/details/53519894 # 二、DelimterBaseFrameDecoder(长度,容器里面的数据) public class Client { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { // ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes()); sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf)); //FixedLengthFrameDecoder(5) //表示固定长度发送消息 不足5位可以用空格补位 sc.pipeline().addLast(new StringDecoder()); sc.pipeline().addLast(new ClientHandler()); } }); ChannelFuture cf = b.connect("127.0.0.1", 8765).sync(); c**f.channel().writeAndFlush(Unpooled.wrappedBuffer("bbbb$_".getBytes())); cf.channel().writeAndFlush(Unpooled.wrappedBuffer("cccc$_".getBytes())); ** //等待客户端端口关闭 cf.channel().closeFuture().sync(); group.shutdownGracefully(); } } public class ClientHandler extends ChannelHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("client channel active... "); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { String response = (String)msg; System.out.println("Client: " + response); } finally { ReferenceCountUtil.release(msg); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } } 服务端 public class Server { public static void main(String[] args) throws Exception{ //1 创建2个线程,一个是负责接收客户端的连接。一个是负责进行数据传输的 EventLoopGroup pGroup = new NioEventLoopGroup(); EventLoopGroup cGroup = new NioEventLoopGroup(); //2 创建服务器辅助类 ServerBootstrap b = new ServerBootstrap(); b.group(pGroup, cGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_SNDBUF, 32*1024) .option(ChannelOption.SO_RCVBUF, 32*1024) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { //设置特殊分隔符 ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes()); sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf)); //设置字符串形式的解码 sc.pipeline().addLast(new StringDecoder()); sc.pipeline().addLast(new ServerHandler()); } }); //4 绑定连接 ChannelFuture cf = b.bind(8765).sync(); //等待服务器监听端口关闭 cf.channel().closeFuture().sync(); pGroup.shutdownGracefully(); cGroup.shutdownGracefully(); } } public class ServerHandler extends ChannelHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(" server channel active... "); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String request = (String)msg; System.out.println("Server :" + msg); String response = "服务器响应:" + msg + "$_"; ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes())); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { ctx.close(); } } # ## 总结: 服务器:为什么叫TCP粘包和,拆包,因为我们在通过http协议socket而Netty又是对socket底层协议的封装,主要是用于 通信协议上的问题 服务器怎么做的呢: 第一步:还是通过管道发布服务, 第二步:发送的内容进行解码 1.DelimiterBasedFrameDecoder(arg1,arg2)限制解码器的大小 2.StringDecoder:加上这个类去管道是说明采用什么样的解码器进行编码 第三步:注入接受和发送的处理器 3.发送信息或者接收信息的管道 客服端具体怎么做的呢 第一步:还是通过管道连接到服务器, 第二步:发送的内容进行解码 1.DelimiterBasedFrameDecoder(arg1,arg2)缓冲大小的大小和指定分隔符 2.StringDecoder:加上这个类去管道是说明采用什么样的解码器进行编码 3.发送信息或者接收信息的管道 第三步:注入接受和发送的处理器 3.发送信息或者接收信息的管道 小结: 客户端通过服务器发送过来的数据进行拆包,通过编码器进行编码,然后放到管道中,接受到进行解码