netty里面FrameDecoder的理解
[color=blue][size=medium]在netty里面,messageReceived的实现如下:
[/size][/color][code="java"]
Object m = e.getMessage();
if (!(m instanceof ChannelBuffer)) {
ctx.sendUpstream(e);
return;
}
ChannelBuffer input = (ChannelBuffer) m;
if (!input.readable()) {
return;
}
ChannelBuffer cumulation = cumulation(ctx);
if (cumulation.readable()) {
cumulation.discardReadBytes();
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
} else {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
if (input.readable()) {
cumulation.writeBytes(input);
}
}
[/code]
[color=blue][size=medium]我们看到比较关键的是cumulation函数,函数如下:
[/size][/color][code="java"]
private ChannelBuffer cumulation(ChannelHandlerContext ctx) {
ChannelBuffer c = cumulation;
if (c == null) {
c = ChannelBuffers.dynamicBuffer(
ctx.getChannel().getConfig().getBufferFactory());
cumulation = c;
}
return c;
}
[/code]
[color=blue][size=medium]在这个里面为什么要这么实现呢,什么时候cumulation不为空呢?
我们再看看上面的实现:[/size][/color]
[code="java"]
if (cumulation.readable()) {
cumulation.discardReadBytes();
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
} else {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
if (input.readable()) {
cumulation.writeBytes(input);
}
}
[/code]
[color=blue][size=medium]这个if和else里面的逻辑应该怎么理解。
[/size][/color]
1、什么时候cumulation不为空呢?
初次运行,cumulation == null,所以ChannelBuffer cumulation = cumulation(ctx);创建了一个空的dynamicBuffer;
cumulation.readable()是false,所以执行的是:
else {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
if (input.readable()) {
cumulation.writeBytes(input);
}
}
callDecode过程中,可能只decode了input的一部分,剩下的字节就写到cumulation,等到下次messageReceived之后,就看到cumulation不为空。(可能messageReceived一次接受了1.5个frame,callDecode只decode了一个frame,剩下的一半写入cumulation)
2、
接着上面,这时候cumulation.readable()是true,所以执行的是
if (cumulation.readable()) {
cumulation.discardReadBytes();
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
}
这里将新接收到的input写入cumulation,然后继续decode。(又接收到了另一半,与先前接收到的合并到一起组成一个完整的frame)
3、源代码文档上说的很清楚了:
在像 TCP/IP这种基于流的传输过程中,即使在局域网环境中,报文也可能被分割和重组。FrameDecoder帮助我们将接受到的报文重新整理成有意义的、容易被应用程序逻辑理解的frames。
In a stream-based transport such as TCP/IP, packets can be fragmented and
- reassembled during transmission even in a LAN environment. For example,
- let us assume you have received three packets:
- +-----+-----+-----+
- | ABC | DEF | GHI |
- +-----+-----+-----+
- because of the packet fragmentation, a server can receive them like the
- following:
- +----+-------+---+---+
- | AB | CDEFG | H | I |
- +----+-------+---+---+ {@link FrameDecoder} helps you defrag the received packets into one or more
- meaningful frames that could be easily understood by the
- application logic. In case of the example above, your {@link FrameDecoder}
- implementation could defrag the received packets like the following:
- +-----+-----+-----+
- | ABC | DEF | GHI |
- +-----+-----+-----+
解码的一个关键就是处理tcp粘包的一个问题,netty将粘包的问题,自己处理了很多。
如果你用mina的话,需要自己去处理这些粘包的问题。看这段代码的话,可以很明白的。