手写RPC框架(十四)

v2.5

尝试心跳 、数据压缩、TCP沾包拆包

  • 心跳机制的实现 Netty源码解析-IdleStateHandler
    实现通过用户设置 多少秒没读 多少秒没写 多少秒没读写进行报读空闲、写空闲、读写空闲
    当客户端一定时间内没有收到相应的请求,就将客户端的连接关闭,服务端是需要持续

    • 注解创建 注解创建结束后配置都在common包中

      • 注解编写

        package annotation;
        
        import java.lang.annotation.ElementType;
        import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
        import java.lang.annotation.Target;
        
        //是否开启的工具类
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface HeartBeatTool {
            boolean isOpenFunction() default false; //是否开启的标志
            int readerIdleTimeSeconds() default 5;  //超过多少时间触发读空闲事件
            int writerIdleTimeSeconds() default 5;  //超过多少时间触发写空闲事件
            int allIdleTimeSeconds() default 3;     //超过多少时间触发读写空闲事件
        }
        
        
      • 注解到配置类上

        package heartbeat;
        
        import annotation.HeartBeatTool;
        
        @HeartBeatTool(isOpenFunction = true,
                readerIdleTimeSeconds = 4,
                writerIdleTimeSeconds = 4,
                allIdleTimeSeconds = 2)
        public interface HeartBeat {
        }
        
    • 心跳事件对应处理器添加构造

      //上面的改造
      private static HeartBeatTool heartBeatToolAnnotation = HeartBeat.class.getAnnotation(HeartBeatTool.class);
      
      /*
      v2.5更新添加读写空闲处理器
      IdleStateHandler是netty提供的处理读写空闲的处理器
      readerIdleTimeSeconds  多长时间没有读 就会传递一个心跳包进行检测
      writerIdleTimeSeconds  多长时间没有写 就会传递一个心跳包进行检测
      allIdleTimeSeconds     多长时间没有读写 就会传递一个心跳包进行检测
      
      当事件触发后会传递给下一个处理器进行处理,只需要在下一个处理器中实现userEventTriggered事件即可
      */
      //时间和实不实现 根据注解 判断是否开启
      //记住后面一定是要有一个处理器 用来处理触发事件
      if (heartBeatToolAnnotation.isOpenFunction())
      {
       pipeline.addLast(new IdleStateHandler(
                                              heartBeatToolAnnotation.readerIdleTimeSeconds(),
                                              heartBeatToolAnnotation.writerIdleTimeSeconds(),
                                              heartBeatToolAnnotation.allIdleTimeSeconds())
           );
      }
      
    • 事件监听处理

          //用来判断是否出现了空闲事件  如果出现了那就进行相应的处理
          @Override
          public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
              if (evt instanceof IdleStateEvent)
              {
                  IdleStateEvent event = (IdleStateEvent) evt;
                  //设置一个事件字段
                  String eventType = null;
                  switch (event.state())
                  {
                      case READER_IDLE:
                          eventType = "读空闲";
                          break;
                      case WRITER_IDLE:
                          eventType = "写空闲";
                          break;
                      case ALL_IDLE:
                          eventType = "读写空闲";
                          break;
                  }
                  System.out.println(ctx.channel().remoteAddress()+"发生超时事件"+eventType+":连接关闭");
                  ctx.close();
              }
          }
      
    • 可以实现保持连接

      • 通过在客户端再设置一个处理器 超过几秒 没发送,就发送一次 ,保持心跳,因为我这边额外的逻辑,如果要实现得重新写一下,对应的处理器 所以下次实现
  • 数据压缩
    对于小体积反而会变大,如果是传输大的对象可以选择开启压缩

    • 书写注解 进行判断是否开启

      package annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      //进行判断解压缩功能是否开启
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface CompressFunction {
          boolean isOpenFunction();
      }
      
      
      //冠上注解
      package compress;
      
      import annotation.CompressFunction;
      
      @CompressFunction(isOpenFunction = true)
      public interface Compress {
      }
      
    • 各个解压缩工具类的实现(要知道它们的区别,同时了解它们的实现方式)

      • bzip

        • 依赖引入

          <!--Bzip依赖引入-->
          <dependency>
              <groupId>org.apache.ant</groupId>
              <artifactId>ant</artifactId>
              <version>1.10.6</version>
          </dependency>
          
        • bzip解压缩工具类

          package compress.bzip;
          
          import compress.CompressTpye;
          import org.apache.tools.bzip2.CBZip2InputStream;
          import org.apache.tools.bzip2.CBZip2OutputStream;
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          
          //apache下的一个解压缩工具 bzip
          public class BZipUtils implements CompressTpye {
          
              private static final int BUFFER_SIZE = 8192;
              @Override
              public byte[] compress(byte[] bytes) throws IOException {
                  //数组输出流
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
                  CBZip2OutputStream cbZip2OutputStream = new CBZip2OutputStream(bos);
                  cbZip2OutputStream.write(bytes);
                  //finish 当压缩结束后 结束
                  cbZip2OutputStream.finish();
                  byte[] request = bos.toByteArray();
          
                  //关闭
                  cbZip2OutputStream.close();
                  bos.close();
          
                  return request;
              }
          
              @Override
              public byte[] deCompress(byte[] bytes) throws IOException {
                  //输入进行解压 再将解压后的传入输出
                  ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                  CBZip2InputStream cbZip2InputStream = new CBZip2InputStream(bis);
          
                  //将输入流中的数据写入
                  ByteArrayOutputStream out = new ByteArrayOutputStream();
                  byte[] buffer = new byte[BUFFER_SIZE];
                  int n;
                  while ((n=cbZip2InputStream.read(buffer))>-1)
                  {
                      out.write(buffer,0,n);
                  }
                  byte[] response = out.toByteArray();
          
                  //关闭对应
                  out.close();
                  cbZip2InputStream.close();
                  bis.close();
          
                  return response;
              }
          }
          
        • 结果
          在这里插入图片描述

      • deflater

        • deflater解压缩工具类(因为这是java.util.zip下自带的工具类不用引入依赖)

          package compress.deflater;
          
          import compress.CompressTpye;
          
          import java.io.ByteArrayOutputStream;
          import java.util.zip.DataFormatException;
          import java.util.zip.Deflater;
          import java.util.zip.Inflater;
          
          public class DeflaterUtils implements CompressTpye {
          
              //固定读取字节数组大小
              private static final int BUFFER_SIZE = 8192;
          
              @Override
              public byte[] compress(byte[] bytes) {
                  int length;
                  Deflater deflater = new Deflater();
                  deflater.setInput(bytes);
                  deflater.finish();
          
                  byte[] outputBytes = new byte[BUFFER_SIZE];
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
                  while (!deflater.finished())
                  {
                      length = deflater.deflate(outputBytes);
                      bos.write(outputBytes,0,length);
                  }
                  deflater.end();
                  return bos.toByteArray();
              }
          
              //解压
              @Override
              public byte[] deCompress(byte[] bytes) throws DataFormatException {
                  int length;
                  Inflater inflater = new Inflater();
                  inflater.setInput(bytes);
                  byte[] outputBytes = new byte[BUFFER_SIZE];
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
                  while (!inflater.finished())
                  {
                      length = inflater.inflate(outputBytes);
                      bos.write(outputBytes,0,length);
                  }
                  inflater.end();
                  return bos.toByteArray();
              }
          }
          
        • 结果
          在这里插入图片描述

      • gzip

        • gzip实现解压缩工具类 (这也是java.util.zip下面的类 不引入依赖 实现过程和)

          package compress.gzip;
          
          import compress.CompressTpye;
          
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          import java.util.zip.GZIPInputStream;
          import java.util.zip.GZIPOutputStream;
          
          //gzip实现解压缩   实现过程和bzip很相似
          public class GZipUtils implements CompressTpye {
              private static final int BUFFER_SIZE = 8192;
              @Override
              public byte[] compress(byte[] bytes) throws IOException {
                  //数组输出流
                  ByteArrayOutputStream bos = new ByteArrayOutputStream();
                  GZIPOutputStream gzipOutputStream = new GZIPOutputStream(bos);
                  gzipOutputStream.write(bytes);
                  gzipOutputStream.flush();
                  //finish 当压缩结束后 结束
                  gzipOutputStream.finish();
                  byte[] request = bos.toByteArray();
          
                  //关闭
                  gzipOutputStream.close();
                  bos.close();
          
                  return request;
              }
          
              @Override
              public byte[] deCompress(byte[] bytes) throws IOException {
          
                  //输入进行解压 再将解压后的传入输出
                  ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                  GZIPInputStream gzipInputStream = new GZIPInputStream(bis);
          
                  //将输入流中的数据写入
                  ByteArrayOutputStream out = new ByteArrayOutputStream();
                  byte[] buffer = new byte[BUFFER_SIZE];
                  int n;
                  while ((n=gzipInputStream.read(buffer))>-1)
                  {
                      out.write(buffer,0,n);
                  }
                  byte[] response = out.toByteArray();
          
                  //关闭对应
                  out.close();
                  gzipInputStream.close();
                  bis.close();
          
                  return response;
              }
          }
          
          
        • 结果
          在这里插入图片描述

      • lz4

        • 依赖引入

          <!--Lz4依赖引入 进行解压缩-->
          <dependency>
              <groupId>org.lz4</groupId>
              <artifactId>lz4-java</artifactId>
              <version>1.7.1</version>
          </dependency>
          
        • lz4实现解压缩工具类

          package compress.lz4;
          
          
          import compress.CompressTpye;
          import net.jpountz.lz4.*;
          
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          
          
          public class Lz4Utils implements CompressTpye {
          
              private static final int BUFFER_SIZE = 8192;
          
              @Override
              public byte[] compress(byte[] bytes) throws IOException {
                  //压缩的工具类吧
                  LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
                  ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
          
                  LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(outputStream,BUFFER_SIZE,compressor);
                  lz4BlockOutputStream.write(bytes);
          
                  lz4BlockOutputStream.close();
                  return outputStream.toByteArray();
              }
          
              @Override
              public byte[] deCompress(byte[] bytes) throws IOException {
                  ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
          
                  LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
                  ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
          
                  LZ4BlockInputStream decompressedInputStream = new LZ4BlockInputStream(inputStream,decompressor);
                  int count;
                  byte[] buffer = new byte[BUFFER_SIZE];
                  while ((count=decompressedInputStream.read(buffer))!=-1)
                  {
                      outputStream.write(buffer,0,count);
                  }
                  decompressedInputStream.close();
                  return outputStream.toByteArray();
              }
          }
          
        • 结果
          在这里插入图片描述

      • zip

        • zip解压缩工具类实现

          package compress.zip;
          
          import compress.CompressTpye;
          
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          import java.util.zip.ZipEntry;
          import java.util.zip.ZipInputStream;
          import java.util.zip.ZipOutputStream;
          
          public class ZipUtils implements CompressTpye {
              private static final int BUFFER_SIZE = 8192;
              @Override
              public byte[] compress(byte[] bytes) throws IOException {
                  ByteArrayOutputStream out = new ByteArrayOutputStream();
                  ZipOutputStream zip = new ZipOutputStream(out);
                  ZipEntry entry = new ZipEntry("zip");
                  entry.setSize(bytes.length);
                  zip.putNextEntry(entry);
                  zip.write(bytes);
                  zip.closeEntry();
                  return out.toByteArray();
              }
          
              @Override
              public byte[] deCompress(byte[] bytes) throws IOException {
                  ByteArrayOutputStream out = new ByteArrayOutputStream();
                  ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(bytes));
                  byte[] buffer = new byte[BUFFER_SIZE];
                  while (zip.getNextEntry()!=null)
                  {
                      int n;
                      while ((n = zip.read(buffer))!=-1)
                      {
                          out.write(buffer,0,n);
                      }
                  }
                  return out.toByteArray();
              }
          }
          
          
        • 结果
          在这里插入图片描述

  • TCP沾包拆包
    因为我直接是一次只传一个字节数组,通过对应对象转成的,所以暂时还遇不到沾包拆包问题,在nio的编写中我解决了沾包拆包的问题v1.1 通过阻塞io解决的
    解决方案

    1. 使用自定义协议 + 编解码器 来解决
    2. 关键就是要解决 服务器端每次读取数据长度的问题,这个问题解决,就不会出现服务器多读或少读数据的问题,从而避免TCP粘包、拆包
  • 测试压缩不压缩所用所占的大小是否变化 同时要比较不同的解压缩方法之间的差异 由来(未看各个方法的原理)
    Java不同压缩算法的性能比较_

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值