zoukankan      html  css  js  c++  java
  • 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拆包粘包的处理方式,下面我们看一下第二种处理方式:

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

  • 相关阅读:
    第一章 基础知识
    第1条:考虑用静态工厂方法代替构造器
    spring cloud(断路器——初学五)
    spring cloud(断路器——初学四)
    spring cloud(服务消费者(利用feign实现服务消费及负载均衡)——初学三)
    在阿里云的ubuntu服务器上安装xampp时出现unable to realloc unable to realloc 8380000 bytes错误
    laravel中ubuntu下执行php artisan migrate总是报错
    windows下安装php依赖关系管理工具composer
    apk下载的网址生成一个二维码
    android apk的签名和权限问题
  • 原文地址:https://www.cnblogs.com/shmilyToHu/p/7094627.html
Copyright © 2011-2022 走看看