• TCP粘包、拆包


    TCP粘包、拆包

    熟悉tcp编程的可能都知道,无论是服务端还是客户端,当我们读取或发送数据的时候,都需要考虑TCP底层的粘包/拆包机制。

    TCP是一个“流”协议,所谓流就是没有界限的遗传数据。可以想象下,如果河里的水就是数据,他们是连成一片的,没有分界线。TCP底层并不了解上层的业务数据具体的含义,它会根据TCP缓冲区的实际情况进行包的划分,也就是说,在业务上,我们一个完整的包可能会被TCP分成多个包进行发送,也可能把多个小包装封装成一个大的数据包发送出去,这就是所谓的TCP粘包、拆包问题。

    分析TCP粘包、拆包问题产生的原因“

      1、应用程序write写入的字节大小大于套接口发送缓冲区的大小

      2、进行MSS大小的TCP分段

      3、以太网帧的payload大于MTU进行IP分片

     下面看一下粘包的现象:

    Client端连续发送3次数据,下面看一下Server端的打印结果:

    可以看到,Server端接收到的结果是连接在一起的,

    这就是粘包的现象。

    TCP粘包、拆包问题解决方案

    粘包拆包问题的解决方案,根据业界的主流协议,有三种方案:

      1消息定长,例如每个报文的大小固定为200个字符,如果不够,空位补空格;

      2在包尾部增加特殊字符进行分割,例如加回车等;

      3讲消息分为消息头和消息体,在消息头中包含表示消息总长度的字段。然后进行业务逻辑的处理

    netty提供了一些基础累:

    1分隔符类DelimiterBasedFrameDecoder(自定义分隔符)

    2FixedLengthFrameDecoder(定长)

    下面看一下如何使用自定义分隔符进行拆包的,

    在Server端,

    接收到Client端传来的buf数据,然后通过 DelimiterBasedFrameDecoder 把数据解析成String类型的数据,看一下下面的相关实现:

    我这边是通过“$_”这个字符串作为分隔符,下面看一下ServerHandler里面的响应代码:

    因为在前面已经转换成String类型了,这边只是确保一下类型,进行了一下强转,这边向客户端发送的数据要是原先的buf数据,不然客户端没办法去解析,

    同样的看一下Client端的程序,Client端的程序与Server端的程序类似:

    看一下ClientHandler代码,ClientHandler端就把server端响应的代码进行了打印:

    看一下运行结果,和原先没有使用分隔F的进行一下对比,看看有什么区别:

    Server端接收到3条Client端发送的数据,没有发生粘包的现象。Client端也收到Server端响应的3条数据。

    这是第一种处理TCP拆包粘包的处理方式,下面我们看一下第二种处理方式:

    只需要把使用的类替换掉,并定义字节的长度,不过需要自己传输的字符串自己添加空格,如果不添加,或者设置的字节太短,都会出现粘包的现象。

  • 相关阅读:
    UVALive 7509 Dome and Steles
    HDU 5884 Sort
    Gym 101194H Great Cells
    HDU 5451 Best Solver
    HDU 5883 The Best Path
    HDU 5875 Function
    卡特兰数
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    Spark Scala Flink版本对应关系
  • 原文地址:https://www.cnblogs.com/shmilyToHu/p/7094627.html
Copyright © 2020-2023  润新知