粘包 拆包(分包) 半包

粘包、拆包、半包理解

TCP是一种面向流的网络层传输协议,在使用TCP作为传输层协议时,可保证数据的顺序性和可靠性。

应用层在使用TCP协议传输数据时,可采取两种方式:

  • 短链接:客户端同服务端完成一次通信(客户端只发送一次请求,并接收到响应),关闭TCP连接;
  • 长连接:客户端持续同服务端进行通信(客户端不停的发送请求,并接收到响应),不关闭TCP连接;

使用短连接时,可通过TCP连接是否关闭判断是否完成了一次请求响应通信。但每次请求必须重建TCP连接,会导致请求响应一会会存在一个TCP握手延时。因此经常使用长连接进行较高频率的请求响应通信。

但在使用长连接时,由于客户端可能会发送多个请求,服务端会同时持续收到数据。服务端接收到的数据中可能包含多个请求数据,此时请求数据是粘连在一起的(粘包),需要进行拆分(拆包)。

还有一种情况,服务端接收到的数据中包含一个不完整的请求数据,剩余数据还未接收到(半包),服务端需要继续接收数据直到接收完整请求数据。

  • 粘包:只会在长连接通信方式中存在,不同的请求数据会被服务端同时接收到,而服务端暂时无法将其请求数据区分为请求1或者请求2。
  • 拆包:将粘连在一起的不同请求数据进行拆分
  • 半包:服务端接收到的请求数据不完整,剩余数据正在传输过程中。

粘包、拆包、半包图示

粘包:服务端接收到的请求数据紧紧挨着,暂时无法分离。

拆包:服务端将接收到的数据拆分为不同的请求数据

半包:拆包过程中发现某个请求数据不完整,需要继续接收数据。

如何拆包、判断半包

如何判断不同请求数据的起始和结束位置,是拆包和判断半包的关键。

常用的方法有两种:

  • 包头(包含包体长度)+包体
  • 包头(包含预定义的界定标识)+包体+包尾(包含预定义的界定标识)

第一种方法,读取固定长度的包头后,可根据包头中指定的包体长度读取包体,直到读取到完整的包体。

  • 问题:如果包头中的包体长度同实际的包体长度不附,会导致后续的所有数据拆包都出现问题,且无法恢复。

第二种方法,在持续读取数据时,需要判断读取的数据中是否出现了界定标识,出现了即可判断是否已到旧包的包尾或者新包的包头。包头和包尾至少存在一个。

  • 问题:读取过程中需一直判断界定标识,在高速传输数据时,会导致微小的处理延时。

http协议可以说是以上两种方法的结合,http header信息通过第二种方法获取,http response body通过第一种方法获取(content-length)。

时间: 2024-10-28 23:46:01

粘包 拆包(分包) 半包的相关文章

【转载】socket的半包,粘包与分包的问题

http://zhaohuiopensource.iteye.com/blog/1541270 首先看两个概念: 短连接: 连接->传输数据->关闭连接    HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.    也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接. 长连接: 连接->传输数据->保持连接 -> 传输数据-> ... ->关闭连接. 长连接指建立SOCKET连接后不管是否使用都

Java 粘包/半包 原理与拆包实战(史上最全)

疯狂创客圈 Java 聊天程序[ 亿级流量]实战系列之13 [博客园 总入口 ] 本文的源码工程:Netty 粘包/半包原理与拆包实战 源码 本实例是<Netty 粘包/半包原理与拆包实战> 一文的源代码工程. 写在前面 大家好,我是作者尼恩. 为了完成了一个高性能的 Java 聊天程序,在前面的文章中,尼恩已经再一次的进行了通讯协议的重新选择. 这就是:放弃了大家非常熟悉的json 格式,选择了性能更佳的 Protobuf协议. 在上一篇文章中,并且完成了Netty 和 Protobuf协议

关于TCP封包、粘包、半包

关于Tcp封包 很多朋友已经对此作了不少研究,也花费不少心血编写了实现代码和blog文档.当然也充斥着一些各式的评论,自己看了一下,总结一些心得. 首先我们学习一下这些朋友的心得,他们是: http://blog.csdn.net/stamhe/article/details/4569530 http://www.cppblog.com/tx7do/archive/2011/05/04/145699.html //……………… 当然还有太多,很多东西粘来粘区也不知道到底是谁的原作,J 看这些朋友

C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解决Socket粘包.半包问题. 更甚至,某些师德有问题的老师,根本就没跟你说过Socket的粘包.半包问题是什么玩意儿. 直到有一天,你的Socket程序在传输信息时出现了你预期之外的结果(多于的信息.不完整的信息.乱码.Bug等等). 任你喊了一万遍“我擦”,依旧是不知道问题出在哪儿! 好了,不说

TCP粘包/拆包问题

无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. TCP粘包/拆包问题说明 假设客户

Netty(三)TCP粘包拆包处理

tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 粘包.拆包问题说明 假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况. 1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包: 2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包; 3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部

Netty的TCP粘包/拆包(源码二)

假设客户端分别发送了两个数据包D1和D2给服务器,由于服务器端一次读取到的字节数是不确定的,所以可能发生四种情况: 1.服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包. 2.服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包. 3.服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包. 4.服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1

[编织消息框架][设计协议]解决粘包半包(下)

接下来介绍netty如何切割分包 学习目的,了解处理业务,方便以后脱离依赖 读者如果不感兴趣或看不懂可以先忽略,难度比较大 LengthFieldBasedFrameDecoder.class public LengthFieldBasedFrameDecoder( ByteOrder byteOrder, //大小端模式 默认大端 ByteOrder BIG_ENDIAN int maxFrameLength, //包Frame netty叫帧概念 最大上限 int lengthFieldOf

netty的解码器和粘包拆包

Tcp是一个流的协议,一个完整的包可能会被Tcp拆成多个包进行发送,也可能把一个小的包封装成一个大的数据包发送,这就是所谓的粘包和拆包问题 粘包.拆包出现的原因: 在流传输中出现,UDP不会出现粘包,因为它有消息边界 1.要发送的数据大于TCP发送缓冲区剩余空间,需要被拆包 2.待发送的数据大于MSS(最大报文长度),TCP在传输前将进行拆包 3.要发送的数据小于TCP发送的缓冲区大小,TCP将多次写入的缓冲区一次发送出去,就会出现粘包 4.接受数据端的应用层没有及时读取TCP接受缓冲区的数据,