码迷,mamicode.com
首页 > 其他好文 > 详细

粘包和拆包

时间:2020-11-18 12:28:40      阅读:5      评论:0      收藏:0      [点我收藏+]

标签:load   返回   方案   strong   空间足   函数   解决   转换   ada   

写在前面

粘包、拆包是 Socket 编程中最常遇见的一个问题,本文只对粘包、拆包现象及发生的原因做简要分析,具体如何解决粘包和拆包的问题,在后续文章中会详细介绍。

什么是粘包、拆包

TCP 是个"流"协议,所谓流,就是没有界限的一串数据(无论你上层是如何封装的数据,到通信层都会转换成“流”的形式,比如 Netty 的 ByteBuf),它会根据 TCP 缓冲区的实际情况进行包的划分,所以实际场景可能是:

对于发送端而言:

  • 当 TCP 发送缓冲区剩余空间不足时,一个完整的包可能会被拆分为多个包进行发送,即可能发生拆包情况。

  • 当 TCP 发送缓冲区剩余空间足够时,多个小的包也有可能被封装成一个大的包进行发送,即可能发生粘包情况。

粘包、拆包产生的原因

上面我们详细了解了 TCP 粘包与拆包,那么为什么会发生粘包和拆包呢,大致上有三个方面的原因:

  1. 即上文描述的那种情况。

  2. Nagle 算法,TCP 默认开启 Nagle 算法,Nagle 算法主要做两件事情:只有上一个分组得到确认,才发送下一个分组,收集多个小分组,在一个确认到来时一起发送,Nagle 算法可能造成发送方粘包。

  3. 进行 MSS 大小的 TCP,MSS 是最大报文段长度的缩写,是 TCP 报文段中的 数据字段 最大长度,MSS = TCP 报文段长度 - TCP 首部长度。

  4. 以太网的 Payload 大于 MTU,进行 IP 分片,MTU 是最大传输单元的缩写,以太网的 MTU 为 1500 字节。

拆包和粘包是相对的,一端粘了包,另外一端就需要将粘过的包拆开

如何处理 TCP 粘包和 TCP 拆包问题?

无论是 TCP 拆包还是 TCP 粘包本质问题都在于无法区分包的边界,一般有三种区分包边界的方式:

  1. 消息数据固定长度,实际应用中基本不可能做到,即时做到了,也是很浪费存储和网络资源。

  2. 使用分割符来区分包的界限

  3. 数据包的头部中增加数据包长度字段

UDP 存在粘包和拆包的问题吗?

TCP 之所以存在拆包和粘包问题,本质就是 TCP 是面向字节流的协议,字节流协议即无边界协议;而像 UDP 是面向报文的,当客户端连续发送多个包,并不会发生粘包现象,每一个包都是独立的,发送的时候也是以一个一个包为单位。

那么问题来了,不会发生粘包,如果应用程序 write 一个大的包,那么到底层进行发送的时候会不会发生拆包呢?

答案是:不会。UDP 协议发送时,用 sendto 函数最大能发送数据的长度为:65535- IP 头(20) - UDP 头(8) = 65507 字节。用 sendto 函数发送数据时,如果发送数据长度大于该值,则函数直接返回错误,不会发生拆包,而 TCP 流协议是会发生拆包的。

sendto 扩展

sendto 是一个计算机函数,指向一指定目的地发送数据,sendto 适用于发送未建立连接的 UDP 数据包 (参数为SOCK_DGRAM)。sendto 发送数据必需注意数据长度不应超过通讯子网的 IP 包最大长度。IP 包最大长度在 WSAStartup() 调用返回的 WSAData 的 iMaxUdpDg 元素中。如果数据太长无法自动通过下层协议,则返回 WSAEMSGSIZE 错误,数据不会被发送。

WSAEMSGSIZE:套接口为 SOCK_DGRAM 类型,且数据报大于 WINDOWS 套接口实现所支持的最大值。

int PASCAL FAR sendto(SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen);

s:一个标识套接口的描述字

buf:含待发送数据的缓冲区

len:buf 缓冲区中数据的长度

flags:调用方式标志位

to:(可选)指针,指向目的套接口的地址

tolen:to 所指地址的长度

总结

到这里关于 TCP 粘包和拆包是什么,产生的原因是什么,以及 UDP 是否也会发生粘包和拆包的问题做了简要分析。这只是关于 TCP 粘包和拆包问题的第一篇文章,后面会详细分析常用的解决方案,以及市面上常用通信框架的解决方案是什么。

参考

粘包和拆包

标签:load   返回   方案   strong   空间足   函数   解决   转换   ada   

原文地址:https://www.cnblogs.com/tkzL/p/13954256.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!