TCP粘包和拆包

概念

  • 粘包:TCP层将应用层多个小的数据包封装成一个大的数据包发送出去;
  • 拆包:TCP层将应用层一个大的数据包拆分成多个小的数据包发送出去;

原因

  TCP层并不感知应用层数据包的具体含义,它会根据TCP缓冲区实际情况进行包的划分,所以对于应用层来说,一个完整的数据包可能会被TCP拆分成多个包进行发送,也可能被合并装成一个大的数据包发送。
这里写图片描述

解决方案

  由于TCP不感知应用层的数据,所以必须由应用层对数据进行拆分和重组,解决方案方案大体分为两种:基于分隔符的解码和基于长度的解码。整体思路是:每次产生OP_READ事件,数据被读到ByteBuf后,检查ByteBuf中是否包含指定分隔符或者达到指定长度,如果满足则解码,否则继续缓存在ByteBuf中,直至满足条件或者超过最大长度上限抛出TooLongFrameException异常。

基于分隔符
  1. 基于换行符拆分消息LineBasedFrameDecoder;
  2. 基于自定义分隔符拆分消息DelimiterBasedFrameDecoder;
基于长度
  1. 基于固定长度拆分消息FixedLengthFrameDecoder;
  2. 基于消息头中的长度字段拆分消息LengthFieldBasedFrameDecoder;

代码示例

  只有ByteBuf中包含指定分隔符或者达到指定长度时,才会进行解码,以FixedLengthFrameDecoder示例:

 @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);
        }
    }

    /**
     * Create a frame out of the {@link ByteBuf} and return it.
     *
     * @param   ctx             the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
     * @param   in              the {@link ByteBuf} from which to read data
     * @return  frame           the {@link ByteBuf} which represent the frame or {@code null} if no frame could
     *                          be created.
     */
    protected Object decode(
            @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if (in.readableBytes() < frameLength) {
            return null;
        } else {
            return in.readSlice(frameLength).retain();
        }
    }

参考:

  1. http://www.infoq.com/cn/articles/netty-codec-framework-analyse?utm_source=infoq&utm_campaign=user_page&utm_medium=link
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值