/* * 接收 * * @param context 上下文 * @param channel 通道 * @param buffer 缓存 * @param readable 缓存可读 * @param bytes 输入缓存 * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的 * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据 * @return 后续动作 * @throws IOException */ private NextAction receive( FilterChainContext context, Channel channel, Buffer buffer, int readable, byte[] bytes, int offset, int limit) throws IOException { for (; ; ) { int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小 buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区 limit += read; // 有效数据变长 readable -= read; // 可读数据变少 UnsafeByteArrayInputStream input = new UnsafeByteArrayInputStream( bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭 Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据 if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象 if (readable == 0) { // 如果没有更多可读数据 channel.setAttribute( BUFFER_KEY, new Object[] {bytes, offset, limit}); // 放入通道属性中,等待下一个Buffer的到来 return context.getStopAction(); } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存 if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够 bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍 } else { // 如果bytes缓存有一段数据已被使用 int len = limit - offset; // 计算有效数据长度 System.arraycopy( bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据 offset = 0; // 移到后,bytes缓存没有数据被使用 limit = len; // 移到后,有效数据都在bytes缓存最前面 } } } else { // 如果解析出一个结果 int position = input.position(); // 记录InputStream用了多少 if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归 throw new IOException("Decode without read data."); } offset = position; // 记录已读数据 context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。 if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据 return context.getInvokeAction( new Object[] { buffer, readable, bytes, offset, limit }); // 正常执行完Filter,并重新发起一轮Filter,继续读 } else { // 否则所有数据读完 return context.getInvokeAction(); // 正常执行完Filter } } } }
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception { int readable = input.readableBytes(); if (readable <= 0) { return; } int off, limit; byte[] buf = mBuffer; if (buf == null) { buf = new byte[bufferSize]; off = limit = 0; } else { off = mOffset; limit = mLimit; } com.antrou.dubbo.remoting.netty4.NettyChannel channel = com.antrou.dubbo.remoting.netty4.NettyChannel.getOrAddChannel( ctx.channel(), url, handler); boolean remaining = true; Object msg; UnsafeByteArrayInputStream bis; try { do { // read data into buffer. int read = Math.min(readable, buf.length - limit); input.readBytes(buf, limit, read); limit += read; readable -= read; bis = new UnsafeByteArrayInputStream(buf, off, limit - off); // decode object. do { try { msg = codec.decode(channel, bis); } catch (IOException e) { remaining = false; throw e; } if (msg == Codec.NEED_MORE_INPUT) { if (off == 0) { if (readable > 0) { buf = Bytes.copyOf(buf, buf.length << 1); } } else { int len = limit - off; System.arraycopy(buf, off, buf, 0, len); // adjust buffer. off = 0; limit = len; } break; } else { int pos = bis.position(); if (off == pos) { remaining = false; throw new IOException("Decode without read data."); } if (msg != null) { out.add(msg); } off = pos; } } while (bis.available() > 0); } while (readable > 0); } finally { if (remaining) { int len = limit - off; if (len < buf.length / 2) { System.arraycopy(buf, off, buf, 0, len); off = 0; limit = len; } mBuffer = buf; mOffset = off; mLimit = limit; } else { mBuffer = null; mOffset = mLimit = 0; } com.antrou.dubbo.remoting.netty4.NettyChannel.removeChannelIfDisconnected(ctx.channel()); } }