TCP通信丢包主要问题及具体问题分析_tcp的客户端发送报文给服务器,不产生丢包或网络阻塞,但是数据不一致是因为-程序员宅基地

技术标签: 网络通信  

  今天在公司问老大,公司的项目底层,是使用的TCP,因为可靠,自动断线重连,在底层都实现了,但是我记得TCP也会有掉包的问题,所以这文章就诞生了——关于TCP掉包的问题,TCP是基于不可靠的网络实现可靠的传输,肯定也会存在掉包的情况。

    如果通信中发现缺少数据或者丢包,那么,最大的可能在于程序发送的过程或者接收的过程出现问题。

    例如服务器给客户端发大量数据,Send的频率很高,那么就有可能在Send时发生错误(原因可能是又多种,可能是程序处理逻辑问题,多线程同步问题,缓冲区溢出问题等等),如果没有对Send失败做处理重发数据,那么客户端收到的数据就会比理论应该收到的少,就会造成丢数据,丢包的现象。
    这种现象,其实本质上来说不是丢包,也不是丢数据,只是因为程序处理有错误,导致有些数据没有成功地被socket发送出去。
 
    常用的解决方法如下:拆包、加包头、发送,组合包,如果客户端、服务端掉线,常采用心跳测试。
 

tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

粘包、拆包问题说明

假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况。

  • 1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包;
  • 2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包;
  • 3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为拆包;
  • 4.服务端分2次读取到了两个数据包,第一次读取到了部分D1,第二次读取D1剩余的部分和完整的D2包;

如果此时服务端TCP接收滑动窗非常小,而数据包D1和D2都很大,很有可能发送第五种可能,即服务端多次才能把D1和D2接收完全,期间多次发生拆包情况。(TCP接收滑动窗:是接收端的大小,随着流量大小而变化,如果我的解释还不明确,请读者自行百度,或者查阅《计算机网络》、《TCP/IP》中TCP的内容)

粘包问题的解决策略

由于底层的TCP无法理解上层的业务逻辑,所以在底层是无法确保数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:

  • 1.消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格;
  • 2.在包尾增加回车换行符进行分割,例如FTP协议;
  • 3.将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路是消息头的第一个字段用int来表示消息的总长度;(我之前linux C开发,就用的这种)。
  • 4.更复杂的应用层协议;
 
作者:orange1438
出处:http://www.cnblogs.com/orange1438/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


UDP主要丢包原因及具体问题分析
 
一、主要丢包原因
 
1、接收端处理时间过长导致丢包:调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。
 
2、发送的包巨大丢包:虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。
 
3、发送的包较大,超过接受者缓存导致丢包:包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
 
4、发送的包频率太快:虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。
 
5、局域网内不丢包,公网上丢包。这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作。
 
 
二、具体问题分析
 
1.发送频率过高导致丢包
 
很多人会不理解发送速度过快为什么会产生丢包,原因就是UDP的SendTo不会造成线程阻塞,也就是说,UDP的SentTo不会像TCP中的SendTo那样,直到数据完全发送才会return回调用函数,它不保证当执行下一条语句时数据是否被发送。(SendTo方法是异步的)这样,如果要发送的数据过多或者过大,那么在缓冲区满的那个瞬间要发送的报文就很有可能被丢失。至于对“过快”的解释,作者这样说:“A few packets a second are not an issue; hundreds or thousands may be an issue.”(一秒钟几个数据包不算什么,但是一秒钟成百上千的数据包就不好办了)。 要解决接收方丢包的问题很简单,首先要保证程序执行后马上开始监听(如果数据包不确定什么时候发过来的话),其次,要在收到一个数据包后最短的时间内重新回到监听状态,其间要尽量避免复杂的操作(比较好的解决办法是使用多线程回调机制)。
 
2.报文过大丢包
 
至于报文过大的问题,可以通过控制报文大小来解决,使得每个报文的长度小于MTU。以太网的MTU通常是1500 bytes,其他一些诸如拨号连接的网络MTU值为1280 bytes,如果使用speaking这样很难得到MTU的网络,那么最好将报文长度控制在1280 bytes以下。
 
3.发送方丢包
 
发送方丢包:内部缓冲区(internal buffers)已满,并且发送速度过快(即发送两个报文之间的间隔过短);  接收方丢包:Socket未开始监听;  虽然UDP的报文长度最大可以达到64 kb,但是当报文过大时,稳定性会大大减弱。这是因为当报文过大时会被分割,使得每个分割块(翻译可能有误差,原文是fragmentation)的长度小于MTU,然后分别发送,并在接收方重新组合(reassemble),但是如果其中一个报文丢失,那么其他已收到的报文都无法返回给程序,也就无法得到完整的数据了。 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LANGZI7758521/article/details/52789793

智能推荐

Java: 理解异常/错误(Error和Exception)_java 错误和异常-程序员宅基地

文章浏览阅读2.1k次。一、Throwable结构在Java中,Throwable是所有错误与异常的超类。Throwable包含两个子类:Error(错误)和Exception(异常)异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理Error: 是程序无法处理的错误,表示运行应用程序中较严重问题. 大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。(如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefF.._java 错误和异常

【算法】数据结构:跳表_跳表level怎么计算-程序员宅基地

文章浏览阅读229次。一、引言在排好顺序的数组中,要查找某个元素,我们可以通过二分法来快速查找,这其实依赖的是数组的随机访问的特性,我可以通过arr[6],来访问数组中的第七个元素(因为第一个元素下标是0),因此我就可以跳跃着访问数组中任意一个元素。但如果是普通的链表,第七个元素的地址,我只能通过第六个元素知道,第六个元素的地址我只能通过第五个元素知道,以此类推,我如果要查找链表中的任意一个元素,我都需要从头遍历,就使用不了二分法查找,那么对于链表这样的数据结构的快速查询,是否有合理的解决方案?有的,把链表变为跳表!_跳表level怎么计算

投光灯高可靠低THD高压线性恒流芯片:SM2255EH-程序员宅基地

文章浏览阅读223次,点赞5次,收藏3次。SM2255EH是一款应用于投光灯、工矿灯、LED照明灯等多种灯具中五段低THD、高功率因数LED线性恒流控制芯片,芯片集成了700V高压MOSFET,采用独特创新的器件工艺技术,具有优越的抗雪崩击穿及浪涌能力,在外围无保护器件时可通过600V雷击浪涌测试,内置过温保护功能,提升系统应用可靠性。其次,这种芯片集成了700V高压MOS管和JFET高压供电功能,能够轻松通过440Vac高压和4kV雷击。高可靠低THD高压线性恒流芯片是一种特殊的电子芯片,主要用于驱动高电压、低电流的LED灯串。

rabbitmq:7.rabbitmq集群,Federation交换机和队列,Shovel_suggestion: check if the erlang cookie is identica-程序员宅基地

文章浏览阅读604次。十、rabbitmq集群10.1. clustering10.1.1. 使用集群的原因最开始我们介绍了如何安装及运行 RabbitMQ 服务,不过这些是单机版的,无法满足目前真实应用的要求。如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等情况,该怎么办?单台 RabbitMQ 服务器可以满足每秒 1000 条消息的吞吐量,那么如果应用需要 RabbitMQ 服务满足每秒 10 万条消息的吞吐量呢?购买昂贵的服务器来增强单机 RabbitMQ 务的性能显得捉襟见肘,搭建一个 Rabbi_suggestion: check if the erlang cookie is identical for all server nodes and

不同编程语言的程序可不可以通过接口相互调用?一些库为啥可以提供不同语言的接口?_跨语言调用api(1)-程序员宅基地

文章浏览阅读892次,点赞12次,收藏30次。为了实现这种融合,必须在所有设备的驱动中设计面向操作系统内核的接口,这样的接口由操作系统规定,对一类设备而言结构一致,独立于具体的设备。融合到系统内核里的设备驱动使用的编程语言是和编写系统所用的语言一致的,例如Linux系统内核是用C语言和汇编语言写的,所以其设备驱动也是用C语言和汇编语言写的。首先,不同编程语言对应不同的编译器,而不同编程语言的编译器对函数的解释不同,会翻译成不同的符号表。函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。

oracle 转义 039,案例:Oracle报错ORA-19583 ORA-27206 ORA-06512-程序员宅基地

文章浏览阅读356次。天萃荷净运维DBA工程师在巡检时发现alert日志存在错误ORA-19583 ORA-27206 ORA-06512,结合mos分析原因为RMAN备份导致报错1.检查alert日志发现近期数据库出现了ORA-19583 ORA-27206 ORA-06512错误Fri Dec 30 12:22:36 2011Errors in file /oracle9/app/admin/ykcdb/udump..._ora-27206

随便推点

36: ansible基础 、 Ansible ad-hoc 、 总结和答疑_unsupported parameters for (file) module: register-程序员宅基地

文章浏览阅读695次。CASE Top NSD AUTOMATION DAY01 案例1:部署Ansible 案例2:Ansible ad-hoc应用一 案例3:Ansible ad-hoc应用二 ..._unsupported parameters for (file) module: register. supported parameters inc

Xj123.biz 新疆维文网址导航站正式开通了!-程序员宅基地

文章浏览阅读1k次。为什么80%的码农都做不了架构师?>>> ..._维文网址

YUV颜色编码解析 ---- Good_16位yuv色彩-程序员宅基地

文章浏览阅读352次。come from :https://www.jianshu.com/p/a91502c00fb0YUVYUV是一种颜色空间,基于YUV的颜色编码是流媒体的常用编码方式。Y表示流明,U、V表示色度、浓度,这种表达方式起初是为了彩色电视与黑白电视之间的信号兼容。 对于图像每一点,Y确定其亮度,UV确认其彩度。Y'CbCr也称为YUV,是YUV的压缩版本,不同之处在于Y'CbCr用于数字..._16位yuv色彩

动态相对定位差分关键技术_动态差分算法-程序员宅基地

文章浏览阅读403次。卫星导航差分定位,动态相对定位关键技术_动态差分算法

ROS问题及解决方案_std::runtime_error' what(): time is out of dual 32-程序员宅基地

文章浏览阅读349次。在.bashrc文件末尾添加:export LC_ALL="C"_std::runtime_error' what(): time is out of dual 32-bit range

java生命周期面试,总结10大门类100道python面试题笔试题,Python阿里等大厂面试题汇总-程序员宅基地

文章浏览阅读349次,点赞5次,收藏4次。① 2000多本Python电子书(主流和经典的书籍应该都有了)② Python标准库资料(最全中文版)③ 项目源码(四五十个有趣且经典的练手项目及源码)④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)⑤ Python学习路线图(告别不入流的学习)