Netty 学习笔记(六)、Netty 如何解决 TCP 粘包/拆包问题

本文介绍了TCP粘包/拆包问题及其原因,包括应用程序write()字节数过大、MSS分段和IP分片等。接着探讨了通过消息定长、包尾换行符、消息头记录长度等方式在应用层解决粘包/拆包的策略。通过一个示例展示了Netty如何使用LineBasedFrameDecoder和StringDecoder来处理粘包问题,实现了按换行符分割数据包并自动编码,从而有效解决了该问题。
摘要由CSDN通过智能技术生成

概述

在早先博客我通过 NIO 实现时间服务器时曾提到:TCP 可能造成粘包/拆包问题,但由于之前的示例相对简单,因此没有做预防处理。本篇博客我就来简单聊一下 TCP 粘包/拆包 问题以及 Netty 如何解决该问题。


什么是 TCP 粘包/拆包问题

TCP 是一种流传输协议,所谓流传输就是指数据包之间没有界限,所有数据都是连在一起的。顶层应用层通过 TCP 发送数据时,TCP 并不了解该数据具体含义,它只会根据当前缓冲区的实际情况进行数据包的划分。这样就可能导致一个完整的业务数据包被拆分为多个TCP包发送或几个完整的数据包黏在一个TCP包中发送,这就是 TCP 的粘包/拆包问题。

举个例子:客户端通过 TCP 发送两个数据包 D1、D2 到服务端,此时对于服务端来说可能存在以下五种情况:

  • 服务端分两次读取到两个独立的数据包,分别是 D1、D2,没有粘包、拆包问题
  • 服务端一次接收到两个数据包,分别是 D1、D2,发生粘包问题
  • 服务端分两次读取到两个数据包,第一个数据包记录完整的 D1 数据和 D2 部分数据,第二个数据包记录剩余 D2 数据,发生拆包问题
  • 服务端分两次读取到两个数据包,第一个数据包记录部分 D1 数据,第二个数据包记录剩余 D1 数据和完整的 D2 数据,发生拆包问题
  • 服务端分多次读取到多个数据包,每个数据包只记录部分数据,发生拆包问题

对于 TCP 不太了解的读者可以 点击这里 查看我之前关于 TCP 整理的博客,下文很多概念会涉及 TCP 相关知识。


粘包/拆包问题发送的原因

发送粘包/拆包问题原因主要集中在以下三点:

  • 应用程序 write() 写入的字节数大于套接口发送缓冲区大小:发送的数据过大,超过此时发送缓冲区大小,此时就必须将数据拆分成多个包发送
  • 进行 MSS 大小的 TCP 分段:MSS 即最大报文长度,即要发送的数据大小已超过最大的报文长度
  • 以太网帧的 payload 大于 MTU 进行 IP 分片:发送的数据过大,超过 IP 层的最大传输单元

MSS(最大报文长度)和 MTU(最大传输单元)的区别和联系:
1、MTU 应用于数据链路层,不针对某个协议,MSS 主要针对 TCP 协议
2、MTU 限制了数据链路层可以传输的数据大小,因此间接影响了上层(网络层)的数据包大小
3、由于 MSS 受 MTU 限制,因此 MSS 值一定小于 MTU

根据 TCP 的流量控制,MSS 会随着网络环境的改变适应性改变,其中它的值受客户端和服务端共同影响。


粘包/拆包问题的解决策略

由于底层 TCP 无法理解上层应用层数据,所以在底层是无法完全解决粘包/拆包问题的。一般只能通过上层应用层来解决:

  • 消息定长:固定每个报文的大小长度
  • 包尾增加换行符,但此时需要特别注意:应用数据中不能包含换行符
  • 消息分为消息头和消息体,消息头中包含属性记录数据长度
  • 更复杂的应用层协议

总得来说,解决该问题的核心思路在于让 TCP 知道数据包之间的间隔。


粘包异常示例

这里我给出可能导致粘包问题的代码,其中省略 Netty 客户端、服务端代码,只保留具体 I/O 处理类:

客户端处理类:

public class TimeClientHandler extends ChannelHandlerAdapter {
   

    /**
     * 用来记录客户端发送的记录数
     */
    private int counter;

    private byte[] bytes = "QUERY TIME ORDER\n".getBytes();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
   
        ByteBuf buf = null;
        for (int i = 0; i < 100; i++)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值