zoukankan      html  css  js  c++  java
  • TCP粘包/拆包问题

    什么是粘包、拆包?

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

    对于什么是粘包、拆包问题,两个简单的应用场景:

    1. 客户端和服务器建立一个连接,客户端发送一条消息,客户端关闭与服务端的连接。

    2. 客户端和服务器建立一个连接,客户端连续发送两条消息,客户端关闭与服务端的连接。

    对于第一种情况,服务端的处理流程可以是这样的:当客户端与服务端的连接建立成功之后,服务端不断读取客户端发送过来的数据,当客户端与服务端连接断开之后,服务端知道已经读完了一条消息,然后进行解码和后续处理。

    对于第二种情况,如果按照上面相同的处理逻辑来处理,那就有问题了,我们来看看第二种情况下客户端发送的两条消息递交到服务端有可能出现的情况:

    第一种情况:

      服务端一共读到两个数据包,第一个包包含客户端发出的第一条消息的完整信息,第二个包包含客户端发出的第二条消息,那这种情况比较好处理,服务器只需要简单的从网络缓冲区去读就好了,第一次读到第一条消息的完整信息,消费完再从网络缓冲区将第二条完整消息读出来消费。

    第二种情况:

      服务端一共就读到一个数据包,这个数据包包含客户端发出的两条消息的完整信息,这个时候基于之前逻辑实现的服务端就蒙了,因为服务端不知道第一条消息从哪儿结束和第二条消息从哪儿开始,这种情况其实是发生了TCP粘包。

    第三种情况:

      服务端一共收到了两个数据包,第一个数据包只包含了第一条消息的一部分,第一条消息的后半部分和第二条消息都在第二个数据包中,或者是第一个数据包包含了第一条消息的完整信息和第二条消息的一部分信息,第二个数据包包含了第二条消息的剩下部分,这被称为TCP拆包,因为发生了一条消息被拆分在两个包里面发送了,同样上面的服务器逻辑对于这种情况是不好处理的。

     

    发生TCP粘包、拆包主要是由于下面一些原因:

    1. 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。

    2. 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。

    3. 进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。

    4. 接收方法不及时读取套接字缓冲区数据,这将发生粘包。

     

    如何处理粘包、拆包问题?

    知道了粘包、拆包问题及根源,那么如何处理粘包、拆包问题呢?TCP本身是面向流的,作为网络服务器,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢?通常会有以下一些常用的方法:

    1. 使用带消息头的协议、消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。

    2. 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息。例如每个报文的大小为固定长度200字节,如果不够,空位补空格。

    3. 设置消息边界,服务端从网络流中按消息边界分离出消息内容。

  • 相关阅读:
    Git上手:四种常见的Git协同工作方式
    Git上手:Git扫盲区
    理解web缓存
    浅谈对技术债的理解
    保护个人隐私,从我做起
    cookie注意事项
    了解JavaScript核心精髓(二)
    简单实现nodejs爬虫工具
    浅谈我所见的CSS组织风格
    利用正则表达式清除多余的空行
  • 原文地址:https://www.cnblogs.com/mengchunchen/p/9617894.html
Copyright © 2011-2022 走看看