switch (messageType) { case PUBLISH: if (qosLevel == 3) { thrownewDecoderException("Illegal QOS Level in fixed header of PUBLISH message (" + qosLevel + ')'); } break;
case PUBREL: case SUBSCRIBE: case UNSUBSCRIBE: if (dupFlag) { thrownewDecoderException("Illegal BIT 3 in fixed header of " + messageType + " message, must be 0, found 1"); } if (qosLevel != 1) { thrownewDecoderException("Illegal QOS Level in fixed header of " + messageType + " message, must be 1, found " + qosLevel); } if (retain) { thrownewDecoderException("Illegal BIT 0 in fixed header of " + messageType + " message, must be 0, found 1"); } break;
case AUTH: case CONNACK: case CONNECT: case DISCONNECT: case PINGREQ: case PINGRESP: case PUBACK: case PUBCOMP: case PUBREC: case SUBACK: case UNSUBACK: if (dupFlag) { thrownewDecoderException("Illegal BIT 3 in fixed header of " + messageType + " message, must be 0, found 1"); } if (qosLevel != 0) { thrownewDecoderException("Illegal BIT 2 or 1 in fixed header of " + messageType + " message, must be 0, found " + qosLevel); } if (retain) { thrownewDecoderException("Illegal BIT 0 in fixed header of " + messageType + " message, must be 0, found 1"); } break; default: thrownewDecoderException("Unknown message type, do not know how to validate fixed header"); } // 解析出来的length结果 intremainingLength=0; // 解析length的时候第1个字节进制是128的0次方 intmultiplier=1; short digit; /** * fixed_header里面的byte2编码特点 它不一定刚好仅仅是1个字节 这个字段本身就是变长的 最少1个字节 最多4个字节 怎么知道是不是变长的 在高7位标识 * 高7位 1表示remain length这个字段需要继续解析后面的字节 0表示这个字段的解析到此为止 * 低0到低6位 才是真正的长度内容 * 最多循环看4个字节 看高7位的表示决定要不要继续解析 */ intloops=0; // 因为remain length至少占1个字节 所以用do...while 不管什么情况先搞出来1个字节拿出来它的内容 看后再看高7位的标识 决定要不要继续 do { // 先拿出来1个字节 digit = buffer.readUnsignedByte(); /** * mqtt不是按照10进制存储的 因为最多只能用4个字节表达remain length 而且每个字节只能用7个位 * 所以mqtt为了28个有效位能表达更大的长度 就用了128进制 * 第1个字节 n1*128^0 * 第2个字节 n2*128^1 * 第3个字节 n3*128^2 * 第4个字节 n4*128^3 */ // 当前这个字节的低7位有效内容拿出来 乘以当前字节的对应的进制 remainingLength += (digit & 127) * multiplier; // 下一个字节的进制在当前进制上成128 multiplier *= 128; loops++; } while ((digit & 128) != 0 && loops < 4); // 高7位置1了就继续 上限解析4个字节
if (outSize > 0) { fireChannelRead(ctx, out, outSize); out.clear();
// Check if this handler was removed before continuing with decoding. // If it was removed, it is not safe to continue to operate on the buffer. // // See: // - https://github.com/netty/netty/issues/4635 if (ctx.isRemoved()) { break; } outSize = 0; }
// Check if this handler was removed before continuing the loop. // If it was removed, it is not safe to continue to operate on the buffer. // // See https://github.com/netty/netty/issues/1664 if (ctx.isRemoved()) { break; }
if (outSize == out.size()) { if (oldInputLength == in.readableBytes() && oldState == state) { thrownewDecoderException( StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " + "data or change its state if it did not decode anything."); } else { // Previous data has been discarded or caused state transition. // Probably it is reading on. continue; } } } catch (Signal replay) { // 解码报错了 并且约定的这个报错是要回滚的情况 比如netty累积的字节流是不够一个完整的协议的 这种情况已经解码出来的数据是不能丢的 只能恢复buf里面的读指针位置 然后等tcp送数据过来 // 再次检查一下这个异常确保是约定的回滚 replay.expect(REPLAY);
// Check if this handler was removed before continuing the loop. // If it was removed, it is not safe to continue to operate on the buffer. // // See https://github.com/netty/netty/issues/1664 if (ctx.isRemoved()) { break; }
// Return to the checkpoint (or oldPosition) and retry. // 在真正解码之前已经保存了read index 现在decode过程中发现buf中数据不够解码成完整的协议 要恢复 就把buf的read index恢复到解码之前就行 intcheckpoint=this.checkpoint; if (checkpoint >= 0) { in.readerIndex(checkpoint); } else { // Called by cleanup() - no need to maintain the readerIndex // anymore because the buffer has been released already. } break; }
if (oldReaderIndex == in.readerIndex() && oldState == state) { thrownewDecoderException( StringUtil.simpleClassName(getClass()) + ".decode() method must consume the inbound data " + "or change its state if it decoded something."); } if (isSingleDecode()) { break; } } } catch (DecoderException e) { throw e; } catch (Exception cause) { thrownewDecoderException(cause); } }