FrameDecoder说白了是解码器,可以将网络数据一帧一帧地解码出来
主要看起messageReceived
public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object m = e.getMessage(); if (!(m instanceof ChannelBuffer)) { ctx.sendUpstream(e); return; } ChannelBuffer input = (ChannelBuffer) m; if (!input.readable()) { return; } if (cumulation == null) { try { // the cumulation buffer is not created yet so just pass the input to callDecode(...) method callDecode(ctx, e.getChannel(), input, e.getRemoteAddress()); } finally { updateCumulation(ctx, input); } } else { input = appendToCumulation(input); try { callDecode(ctx, e.getChannel(), input, e.getRemoteAddress()); } finally { updateCumulation(ctx, input); } } }
这里这个cumulation是关键,cumulation的是"累计的意思",即将数据累计起来,首先判断cululation是不是null,是null的话直接调用callDecode方法,不然先将input添加到culutation
callDecode()
private void callDecode( ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, SocketAddress remoteAddress) throws Exception { while (cumulation.readable()) { int oldReaderIndex = cumulation.readerIndex(); Object frame = decode(context, channel, cumulation); if (frame == null) { if (oldReaderIndex == cumulation.readerIndex()) { // Seems like more data is required. // Let us wait for the next notification. break; } else { // Previous data has been discarded. // Probably it is reading on. continue; } } else if (oldReaderIndex == cumulation.readerIndex()) { throw new IllegalStateException( "decode() method must read at least one byte " + "if it returned a frame (caused by: " + getClass() + ")"); } unfoldAndFireMessageReceived(context, remoteAddress, frame); } }
在unfoldAndFireMessageReceived()里面,会调用Channels.fireMessageReceived(),最后调用ctx.sendUpstream,事件会交给下一个Handler来处理
ChannelHandlerContext context, SocketAddress remoteAddress, Object result) { if (unfold) { if (result instanceof Object[]) { for (Object r: (Object[]) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else if (result instanceof Iterable<?>) { for (Object r: (Iterable<?>) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } }appendToCumulation()这里可以看出cumulation是CompositeChannelBuffer,当之前还有buffer没处理完时,与这次的buffer合并一起进行解码
protected ChannelBuffer appendToCumulation(ChannelBuffer input) { ChannelBuffer cumulation = this.cumulation; assert cumulation.readable(); if (cumulation instanceof CompositeChannelBuffer) { // Make sure the resulting cumulation buffer has no more than the configured components. CompositeChannelBuffer composite = (CompositeChannelBuffer) cumulation; if (composite.numComponents() >= maxCumulationBufferComponents) { cumulation = composite.copy(); } } this.cumulation = input = ChannelBuffers.wrappedBuffer(cumulation, input); return input; }另外一个函数时finally里面的updateCumulation()
protected ChannelBuffer updateCumulation(ChannelHandlerContext ctx, ChannelBuffer input) { ChannelBuffer newCumulation; int readableBytes = input.readableBytes(); if (readableBytes > 0) { int inputCapacity = input.capacity(); // If input.readableBytes() == input.capacity() (i.e. input is full), // there‘s nothing to save from creating a new cumulation buffer // even if input.capacity() exceeds the threshold, because the new cumulation // buffer will have the same capacity and content with input. if (readableBytes < inputCapacity && inputCapacity > copyThreshold) { // At least one byte was consumed by callDecode() and input.capacity() // exceeded the threshold. cumulation = newCumulation = newCumulationBuffer(ctx, input.readableBytes()); cumulation.writeBytes(input); } else { // Nothing was consumed by callDecode() or input.capacity() did not // exceed the threshold. if (input.readerIndex() != 0) { cumulation = newCumulation = input.slice(); } else { cumulation = newCumulation = input; } } } else { cumulation = newCumulation = null; } return newCumulation; }
在这个函数里面会对cumulation进行操作修改。这个是在finally,也就是对剩余的数据进行暂时的存取,因为不管是这个buffer比一帧数据大或者小,都不能只是一帧数据,少于一帧不能解码出来,大于一帧势必会有一部分需要暂时存取