docs: WebSocketPacket decode(final Logger logger, final WebSocketRunner runner, final WebSocket webSocket, final int wsmaxbody,
          final AbstractMap.SimpleEntry<String, byte[]> halfBytes, final ByteBuffer buffer) {
          //开始
          final boolean debug = false; //调试开关
          if (debug) logger.log(Level.FINEST, "read websocket message's length = " + buffer.remaining());
          if (!buffer.hasRemaining()) return NONE;
          if (buffer.remaining() < 2) {
              byte[] bs = new byte[buffer.remaining()];
              buffer.get(bs);
              halfBytes.setValue(bs);
              return NONE;
          }
          final byte opcode = buffer.get();   //第一个字节
          this.last = (opcode & 0b1000_0000) != 0;
          this.type = FrameType.valueOf(opcode & 0xF);
  
          if (type == FrameType.CLOSE) {
              if (debug) logger.log(Level.FINEST, " receive close command from websocket client");
          }
          if (type == null) {
              logger.log(Level.SEVERE, " receive unknown frametype(opcode=" + (opcode & 0xF) + ") from websocket client");
          }
          final boolean checkrsv = false;//暂时不校验
          if (checkrsv && (opcode & 0b0111_0000) != 0) {
              if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + opcode + ")");
              return null; //rsv1 rsv2 rsv3 must be 0     
          }
          //0x00 表示一个后续帧 
          //0x01 表示一个文本帧 
          //0x02 表示一个二进制帧 
          //0x03-07 为以后的非控制帧保留
          //0x8 表示一个连接关闭
          //0x9 表示一个ping
          //0xA 表示一个pong
          //0x0B-0F 为以后的控制帧保留
          final boolean control = (opcode & 0b0000_1000) != 0; //是否控制帧
          final byte crcode = buffer.get();  //第二个字节
  
          byte lengthCode = crcode;
          final boolean masked = (lengthCode & 0x80) == 0x80;
          if (masked) lengthCode ^= 0x80; //mask
  
          //判断Buffer剩余内容够不够基本信息的创建
          int minBufferLength = ((lengthCode <= 0x7D) ? 0 : (lengthCode == 0x7E ? 2 : 4)) + (masked ? 4 : 0);
          if (buffer.remaining() < minBufferLength) {
              byte[] bs = new byte[2 + buffer.remaining()];
              bs[0] = opcode;
              bs[1] = crcode;
              buffer.get(bs, 2, buffer.remaining());
              halfBytes.setValue(bs);
              return NONE;
          }
  
          int length;
          if (lengthCode <= 0x7D) { //125
              length = lengthCode;
          } else {
              if (control) {
                  if (debug) logger.log(Level.FINE, " receive control command from websocket client");
                  return null;
              }
              if (lengthCode == 0x7E) {//0x7E=126
                  length = (int) buffer.getChar();
              } else if (lengthCode == 0x7F) {//0x7E=127
                  length = (int) buffer.getLong();
              } else {
                  length = buffer.getInt();
              }
          }
          if (length > wsmaxbody && wsmaxbody > 0) {
              logger.log(Level.WARNING, "message length (" + length + ") too big, must less " + wsmaxbody + "");
              return null;
          }
          this.receiveLength = length;
          if (debug) logger.finest("this.receiveLength: " + length + ", code=" + lengthCode + ", last=" + last);
          if (masked) {
              final byte[] masks = new byte[4];
              buffer.get(masks);
              this.receiveMasker = new ConvertMask() {
  
                  private int index = 0;
  
                  @Override
                  public byte unmask(byte value) {
                      return (byte) (value ^ masks[index++ % 4]);
                  }
              };
          }
          if (buffer.remaining() >= this.receiveLength) { //内容足够， 可以解析
              this.parseReceiveMessage(logger, runner, webSocket, buffer);
              this.receiveCount = this.receiveLength;
          } else {
              this.receiveCount = buffer.remaining();
              this.receiveBuffers = buffer.hasRemaining() ? new ByteBuffer[]{buffer} : null;
          }
          return this;
      }