Netty处理CP粘包和拆包问题和解决方法

概述

TCP是个“流”协议,所谓流,就是没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题

在这里插入图片描述

如图所示,假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4种情况。

  1. 服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包;
  2. 服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包;
  3. 服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包
  4. 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包。

粘包和拆包的解决方法

  1. 消息长度固定,累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息
  2. 将回车换行符作为消息结束符
  3. 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符
  4. 通过在消息头中定义长度字段来标识消息的总长度
  5. 自定义协议

自定义协议

通常很多时候netty自带的处理器不满足我们的需求,所以我们必须在TCP上实现我们自己的协议

通常协议的格式如下:

协议头消息长度消息体

案例

// 协议实体
class Message {
    private String token; // 令牌
    private int headerData = 0XFF1903; // 协议的开始
    private long length; // 消息体长度
    private String message; // 消息体
    // ... 还可以有其它属性
}
public class MessageEncoder extends MessageToByteEncoder<Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 写入协议头
        ctx.writeInt(msg.headerData);
        // 写入消息体长度
        ctx.writeLong(msg.length);
        // 写入消息token,token固定32个长度
        ctx.write(msg.token.toBytes());
        // 写入主体
        ctx.write(msg.message.toBytes());
        // 推送写入的消息
        ctx.flush();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值