TCP-缓冲区和粘包、拆包有什么关系?

    欢迎你们搜索“小猴子的技术笔记”关注个人公众号,领取丰富面试资料和学习资料。java

    你了解TCP缓冲区吗?它和TCP传输中的粘包和拆包有什么关系呢?粘包和拆包分别发生在TCP的那个阶段呢?程序员

    先简单回顾下TCP概念:在网络传输中TCP是面向链接的、可靠的、双通道、字节流一对一传输。TCP双方通讯必需要先创建链接,而后分配必要的内核资源。双方交换完毕数据以后必须都要断开链接用来释放系统资源,长连接能够没必要断开链接复用同一个通道。那么什么是TCP的缓冲区呢?面试

    操做系统中有两个空间:用户空间和内核空间。每个socket链接都是在内核空间,内核针对每个socket都有一个发送缓冲区和接收缓冲区。TCP的双工工做模式以及流量控制就是依赖这两个缓冲区的填充来实现的。算法

    咱们以前用socket获取“OutputStream”获取一个输出流进行字节的写出,实际上是写入到了“send buffer”发送缓冲区中,这个时候数据不必定会发送到对方机器上。“write()”方法仅仅是将用户空间数据拷贝到了内核发送缓冲区中,具体何时发送由TCP决定。网络

    TCP会从发送缓冲区中把数据经过网卡发送到目标机器的内核缓冲区中。若是系统一直没有调用"recv()"方法进行读取的话,那么数据将会一直挤压在socket的recv buffer中。
在这里插入图片描述
    TCP 粘包、拆包问题的由来:socket

    若是你看懂了上面这幅图的话,那么对于粘包和拆包的问题就比较好理解了。在这里我想先问一个问题,粘包和拆包是发生在传输过程当中吗?性能

    粘包和拆包问题究竟发生在什么阶段?首先咱们须要清楚地了解TCP数据是可靠的,所以确定不是传输的过程当中!由于数据发送是从缓冲区->网卡,所以粘包问题是从缓冲区读取数据的时候发生的。拆包则是从缓冲区到网卡的阶段发生的。学习

    这里先解释下粘包:所谓的粘包就是发送方在同一时刻发出了两个或者两个以上的包到接收端。spa

    假设发送端须要发送两条数据“别紧张,你这样没事的!”和“好好看文章,你必定能够学会”。首先会把这两条数据放到发送缓冲区中,而后在通过网卡进行数据的发送到接收方的接收缓冲区中。若是接收方没有及时从接收缓冲区中获取往外取数据,那么数据就会在缓冲区挤压,这样两条数据就会积压在一块,就成了一条数据,这就是粘包的问题!
在这里插入图片描述
    那么什么是拆包问题呢?拆包问题是TCP每次发送的长度是有限制的,若是发送一个包的数据过大的话,TCP就会把这个包拆成两个包来进行发送。操作系统

    假设要发送的数据“别紧张,你这样没事的!”很大,TCP在发送的时候把它拆成了“别紧张,你这样”和“没事的!”进行发送,那么在接收方就会收到两个报文,这就是拆包的问题。
在这里插入图片描述
    实际上过大的话,还有可能会被拆成三个或者更多的包进行发送。可是不管被拆成几个包,TCP都可以保证发送包的顺序性和正确性。

    那么产生粘包和拆包的缘由是什么呢?这个和TCP的缓冲区与滑块窗口、MSS/MTU限制、Nagle算法有关。

    有了粘包和拆包的问题,咱们在实际的开发中应该怎么避免或者处理这个问题呢?那就是定义咱们的通信协议。这样若是粘包了就能够根据协议来区分不一样的包,若是拆包了就等待数据构成一个完整的消息以后在进行处理。

    第一种方式---定长协议:所谓的定长协议就是指定一个报文的固定长度,每次双方按照约定截取固定的长度。假设咱们须要发送“hello”和“very”两个单词,按照约定的5个字节进行一次截取。那么不足5个字节的单词能够添加0做为补充,则发生的规则以下。
在这里插入图片描述
    因为不足约定长度的须要进行补0,所以定长协议会形成带宽的浪费。

    第二种方式---特殊字符分隔符:使用特殊字符分隔符就是在报文的结尾进行追加特殊字符分隔符,用次分隔符来标注这是一个完整的报文,例如遇到了“\n”。
在这里插入图片描述

    这样虽然能够对报文进行划分,可是要求就是报文中不能包含特殊分隔符。

    第三种方式---固定头长度:发送数据以前,须要先获取须要发送内容的二进制字节大小,而后在须要发送的内容前面添加一个固定长度头整数,表示消息体二进制字节的长度。
在这里插入图片描述

    这种方式避免了特殊字符带来的问题,是生产中能够采起的一个方式,我在以前的文章中有介绍过这样的使用方法。

    其实对于java程序员来讲,咱们没必要过度关心接收和发送缓冲区,须要了解其概念,由于底层已经为咱们作了封装。明白“粘包”和“拆包”发生的过程和缘由。

    经过观察用户空间和内核空间的数据交互,你也许会发现进行一次完整的交互须要进行四次的数据拷贝,这在性能上可能会有所影响。这也就有了面试官常常问的“零拷贝”的问题,尝试着本身对本文的理解学习一下“零拷贝”,这是为后面学习Netty打下坚实的基础。

相关文章
相关标签/搜索