TCP-stick package, and half a pack process Netty

References: Time Geeks Fu Jian teacher "Netty source code analysis and practical" Talk is cheap.show me the code!

What is the stick pack and half a pack

  When the client sends data, data is actually written to the TCP transmission buffer inside.

  Half pack: name suggests is half received packet, if the packet size transmitted from the transmission buffer capacity than TCP, then the packet is divided into a plurality of packets, sent to the server through multiple socket, a first server from time to accept the data cache inside the acquisition, is actually part of the whole package, half a pack not to say that only received half of the all-inclusive, and is said to receive a part of the whole package.

   Stick package: If the size of packets sent over TCP send buffer size is small, and the cache can store multiple TCP packet, then a communications client and server may transmit multiple packets, this time from the server to accept the buffer may read more about the package

For chestnut:

  We are now sending two messages: "ABC", "DEF" , then the other received message is not necessarily in this format, they may just received a one-time "ABCDEF", may also be divided several times received the "AB" , "CD", "EF" , or even worse once the message is received two "a", "BCDEF". Then receiving such a message is called a stick package two phenomena , a plurality of the received three times four phenomenon is incomplete half a pack phenomenon.

Stick package main reasons:

  Each time data is written to the sender <socket buffer size, the receiver reads the data socket buffer is not enough time.

Half a pack of the main reasons:

   The sender writes data MTU> socket buffer size, there is the data transmission is greater than a protocol (Maximum Transmission Unit MTU) when necessary unpacking. (MTU is actually the size of each TCP protocol)

Another angle:

  A transceiver: a transmission can be received multiple times, multiple transmissions may be received once

  Transmission: transmission may occupy a plurality of transmission packets, a plurality of common transmission packet transmittable

root cause:

  TCP is a protocol flow, no message boundaries. (UDP as parcel post, although more than one transport, but each package has a "boundary", a a sign, so no stick package, half a pack issue)

Fundamental means to solve the problem: to find the boundary message

  

Netty对三种常用封帧方式的支持(三个类都继承ByteTomessageDecoder.java)

 解读Netty处理粘包、半包的源码-------解码核心工作流程:

  先找到ByteToMessageDecoder.java,可以看到它继承了ChannelInboundHandlerAdapter.java

 这个ChannelInboundHandlerAdapter有个核心的入口方法“channelRead()”;

 图中的msg就相当于我们的数据,开始就把数据转换成data,

ByteBuf data = (ByteBuf) msg;

 

然后判断cumulation是否为null,cumulation是数据积累器,用来积累数据。

ByteBuf cumulation;

 

first = cumulation == null;
if (first) {
    cumulation = data;
 } else {
     cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
 }

 

第一次的时候肯定为null  所以first是true,直接把data数据给了cumulation。再接下来就是接码:

 callDecode(ctx, cumulation, out);

 

进入具体方法

参数中的in就是数据积累器中的数据,也就是我们传入的数据。往下走又这么个方法调用:

decodeRemovalReentryProtection(ctx, in, out);

 

需要注意的是:decode中时,不能执行完handler remove清理操作,decode完之后需要清理数据,改方法的名称长久是标识功能的。点进去可以查看

可以看出有个decodeState = STATE_CALLING_CHILD_DECODE;这个就是处理刚才remove handler 的;接下来就是“decode(ctx, in, out);”;这个decode是个抽象方法

之前说过Netty对三种封帧的支持分别是:“FixedLengthFrameDecoder”,“DelimiterBasedFrameDecoder”,“LengthFieldBasedFrameDecoder”。这里以“FixedLengthFrameDecoder”为例,所以点开FixedLengthFrameDecoder的decode();

   @Override
    protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        Object decoded = decode(ctx, in);
        if (decoded != null) {
            out.add(decoded);
        }
    }

 

然后再进去查看Object decoded = decode(ctx, in);

protected Object decode(
            @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if (in.readableBytes() < frameLength) {
            return null;
        } else {
            return in.readRetainedSlice(frameLength);
        }
    }

 

这时候就能发现关键点,代码标粗,这个in还是数据积累器的数据,取得之后进行判断,如果小于则返回null不能解出,否则解出。这样一来就完成了一个数据解析的过程。

我只想做的更好,仅此而已

Guess you like

Origin www.cnblogs.com/-qilin/p/11686539.html