文章目录

  • 一、为什么TCP会粘包,UDP不会粘包
  • 二、 TCP粘包现象产生原因
    • (1) 发送方
    • (2) 接收方
  • 三、粘包处理方式
    • 发送方的处理方式
    • 接收方的处理方式
    • 应用层的处理方式
    • 封包处理粘包问题
      • (1)动态缓冲区暂存方式
      • (2)利用底层的缓冲区来进行拆包
  • 总结

一、为什么TCP会粘包,UDP不会粘包

TCP是面向流的的传输协议,发送端可以一次发送不定长度的数据,而接收端也可以一次提取不定长度的数据。即这种传输方式是无保护消息边界的。

UDP是面向数据报的传输协议,发送的UDP报文都被接收端视为一条消息,若消息太长被分片,UDP协议也会完成组合后才呈现在内核缓冲区;且UDP报文有消息头,对于接收端来说,易于区分处理。即这种传输方式是有保护消息边界的。


二、 TCP粘包现象产生原因

发送方和接收方对数据的处理都有可能引发粘包现象

(1) 发送方

TCP为了提高传输效率,会在收集到足够多数据后才一起发送,同时一条数据太长,TCP还会将数据进行拆分发生。这将会导致三种情况发生:

  1. 多条数据被组合成一条数据发送
  2. 长数据被拆分成片段分别发送
  3. 长数据被拆分的片段和短数据一起发送

(2) 接收方

接收方收到的数据会保存在缓存中,如果应用层提取数据不够快就会导致缓存中多条数据粘在一起


三、粘包处理方式

也不是所有时候都要去处理粘包,比如如果类似于文件传输这样发送的数据无结构,那么接收方正常接受存储就行,不必考虑分包问题。
只有在TCP长链接且发送不同结构数据时(数据毫不相干,或者必须分开解读),那就要处理粘包问题了

发送方的处理方式

可以关闭Nagle算法,通过TCP_NODELAY选项来关闭。缺点是TCP传输效率降低

Nagle算法主要做两件事:1)只有上一个分组得到确认,才会发送下一个分组;2)收集多个小分组,在一个确认到来时一起发送。正是Nagle算法造成了发送方有可能造成粘包现象。

接收方的处理方式

TCP中接收方无法处理!

应用层的处理方式

应用层的处理简单易行!并且不仅可以解决接收方造成的粘包问题,还能解决发送方造成的粘包问题。
解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?

  • 格式化数据,每条数据都要实现约定好格式(开始符、结束符),显而易见在数据内部中不能出现开始符和结束符!
  • 发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。

封包处理粘包问题

所谓封包,就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容,包头其实上是个大小固定的结构体,其中有个结构体成员变量表示包体的长度,这是个很重要的变量,其他的结构体成员可根据需要自己定义。根据包头长度固定以及包头中含有包体长度的变量就能正确地拆分出一个完整的数据包。对于拆包,目前最常用的是以下两种方式:

(1)动态缓冲区暂存方式

动态是指当需要缓冲的数据长度超出缓冲区的长度时会增大缓冲区长度
大概过程描述如下:

  1. 为每一个连接动态分配一个缓冲区,同时把此缓冲区和SOCKET关联,常用的是通过结构体关联
  2. 当接收到数据时首先把此段数据存放在缓冲区中
  3. 判断缓存区中的数据长度是否够一个包头的长度,如不够,则不进行拆包操作
  4. 根据包头数据解析出里面代表包体长度的变量
  5. 判断缓存区中除包头外的数据长度是否够一个包体的长度,如不够,则不进行拆包操作
  6. 取出整个数据包,这里的"取"的意思是不光从缓冲区中拷贝出数据包,而且要把此数据包从缓存区中删除掉,删除的办法就是把此包后面的数据移动到缓冲区的起始地址(环形缓冲可以优化这里)

这种方法有两个缺点:

  • 为每个连接动态分配一个缓冲区增大了内存的使用.
  • 有三个地方需要拷贝数据,一个地方是把数据存放在缓冲区,一个地方是把完整的数据包从缓冲区取出来,一个地方是把数据包从缓冲区中删除.第二种拆包的方法会解决和完善这些缺点.

可以采用环形缓冲(定义两个指针,分别指向有效数据的头和尾,在存放数据和删除数据时只是进行头尾指针的移动),但是还是不能解决第一个缺点以及第一个数据拷贝,只能解决第三个地方的数据拷贝(这个地方是拷贝数据最多的地方)。第2种拆包方式会解决这两个问题。

(2)利用底层的缓冲区来进行拆包

由于TCP也维护了一个缓冲区,所以我们完全可以利用TCP的缓冲区来缓存我们的数据,这样一来就不需要为每一个连接分配一个缓冲区了。另一方面我们知道recv或者wsarecv都有一个参数,用来表示我们要接收多长长度的数据.利用这两个条件我们就可以对第一种方法进行优化。

直接用底层的缓冲区直接进行拆包,固然可以免于拷贝到缓冲区,但是这样每次接收,都要做逻辑处理,对于频繁接收数据的场景,这种方法效率并不高。而如果我们一次性接收到很多数据,然后利用动态缓冲区暂存,进行异步处理。一次接收,多次处理,效率反而会更高。


总结

以上就是关于TCP粘包问题的粗浅了解

TCP粘包现象分析及处理方式相关推荐

  1. TCP粘包问题分析和解决(全)

    TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...

  2. Python之路(第三十一篇) 网络编程:简单的tcp套接字通信、粘包现象

    一.简单的tcp套接字通信 套接字通信的一般流程 服务端 server = socket() #创建服务器套接字server.bind() #把地址绑定到套接字,网络地址加端口server.liste ...

  3. TCP粘包问题以及解决方法

    粘包问题分析与对策 TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾. 出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方 ...

  4. TCP粘包以及粘包处理

    TCP粘包现象 TCP粘包通俗来讲,就是发送方发送的多个数据包,到接收方后粘连在一起,导致数据包不能完整的体现发送的数据. TCP粘包原因分析 导致TCP粘包的原因,可能是发送方的原因,也有可能是接受 ...

  5. TCP通信粘包问题分析和解决

    在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的 ...

  6. 【Netty】入门Netty官方例子解析(三)处理一个基于流的传输 TCP粘包和拆包问题分析和解决

    关于 Socket Buffer的一个小警告 基于流的传输比如 TCP/IP, 接收到数据是存在 socket 接收的 buffer 中.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列. ...

  7. socket Php 粘包,python3 tcp的粘包现象和解决办法解析

    这篇文章主要介绍了python3 tcp的粘包现象和解决办法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 服务器端 import socket ...

  8. netty权威指南学习笔记三——TCP粘包/拆包之粘包现象

    TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...

  9. 【Netty入门】TCP 粘包/拆包问题产生原因

    TCP粘包/分包问题的由来 因为TCP是以流的方式来处理数据,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送. 这样说可能比较抽象,下面举例来说明TCP拆包/粘包 ...

  10. 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)

    一.粘包/拆包概念 TCP是一个"流"协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的 ...

最新文章

  1. Xamarin环境搭建
  2. oracle cpu 利用率过高 kswapd0_服务器带宽监测与利用率过高的解决办法
  3. 试图抓取非英文windows操作系统镜像时PE无法正常启动解决方法
  4. 在哪开启oracle服务器,开启企业殿堂的钥匙 Oracle服务器的安装
  5. 电容的q值计算公式_在设计电路中电容容量大小、耐压等级选取详解 (转)
  6. 通过ActiveX执行文件
  7. Badboy录制测试脚本
  8. CVPR 2020 论文大盘点—目标跟踪篇
  9. ES6-symbol-使用symbol
  10. 2017.3.30 时态同步 失败总结
  11. Eclipse搭建springboot项目(六)全局异常
  12. 微博认证怎么弄黄v:微博兴趣认证指定领域
  13. adb 版本更新后执行依旧是旧版本解决方法
  14. 苏秋贵:你为什么放弃了多年坚持的制造业?
  15. JavaScript-197:模拟京东快递单号查询案例
  16. QUIC会成为互联网传输的颠覆者吗?
  17. 虚拟机上的hadoop localhost:8088,localhost:50070均不能访问
  18. poco 连接mysql_[Poco]数据库操作简介
  19. 基于STM32和阿里云的智能家居
  20. themeforest 模板

热门文章

  1. 如何设置windows服务
  2. 漂浮广告代码html,漂浮广告的JS代码(经典)
  3. (概率论习题册题解)第二章 随机变量及其分布
  4. C++里中文转拼音那点事
  5. 首都师范 博弈论 3 4 2反复剔除严格劣策略
  6. Mac环境配置MySQL(详细)
  7. 机器学习教程之语义分割入门教程
  8. GitLab使用教程(详细)(转载)
  9. APDU应用协议数据单元
  10. r语言调用python_如何在Rstudio中使用python 语言 (图文详解)