`
moor212
  • 浏览: 173896 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解决TCP网络传输“粘包”问题

 
阅读更多
解决TCP网络传输“粘包”问题


原文出处:http://www.ciw.com.cn/

当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API)。TCP/IP传输层有两个并列的协议:TCP和UDP。其中TCP(transport control protocol,传输控制协议)是面向连接的,提供高可靠性服务。UDP(user datagram protocol,用户数据报协议)是无连接的,提供高效率服务。在实际工程应用中,对可靠性和效率的选择取决于应用的环境和需求。一般情况下,普通数据的网络传输采用高效率的udp,重要数据的网络传输采用高可靠性的TCP。
在应用开发过程中,笔者发现基于TCP网络传输的应用程序有时会出现粘包现象(即发送方发送的若干包数据到接收方接收时粘成一包)。针对这种情况,我们进行了专题研究与实验。本文重点分析了TCP网络粘包问题,并结合实验结果提出了解决该问题的对策和方法,供有关工程技术人员参考。

一、TCP协议简介
  TCP是一个面向连接的传输层协议,虽然TCP不属于iso制定的协议集,但由于其在商业界和工业界的成功应用,它已成为事实上的网络标准,广泛应用于各种网络主机间的通信。

  作为一个面向连接的传输层协议,TCP的目标是为用户提供可靠的端到端连接,保证信息有序无误的传输。它除了提供基本的数据传输功能外,还为保证可靠性采用了数据编号、校验和计算、数据确认等一系列措施。它对传送的每个数据字节都进行编号,并请求接收方回传确认信息(ack)。发送方如果在规定的时间内没有收到数据确认,就重传该数据。数据编号使接收方能够处理数据的失序和重复问题。数据误码问题通过在每个传输的数据段中增加校验和予以解决,接收方在接收到数据后检查校验和,若校验和有误,则丢弃该有误码的数据段,并要求发送方重传。流量控制也是保证可靠性的一个重要措施,若无流控,可能会因接收缓冲区溢出而丢失大量数据,导致许多重传,造成网络拥塞恶性循环。TCP采用可变窗口进行流量控制,由接收方控制发送方发送的数据量。

  TCP为用户提供了高可靠性的网络传输服务,但可靠性保障措施也影响了传输效率。因此,在实际工程应用中,只有关键数据的传输才采用TCP,而普通数据的传输一般采用高效率的udp。

二、粘包问题分析与对策

  TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

  出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据(图1所示)。


图1


图2


图3

  粘包情况有两种,一种是粘在一起的包都是完整的数据包(图1、图2所示),另一种情况是粘在一起的包有不完整的包(图3所示),此处假设用户接收缓冲区长度为m个字节。

  不是所有的粘包现象都需要处理,若传输的数据为不带结构的连续流数据(如文件传输),则不必把粘连的包分开(简称分包)。但在实际工程应用中,传输的数据一般为带结构的数据,这时就需要做分包处理。

  在处理定长结构数据的粘包问题时,分包算法比较简单;在处理不定长结构数据的粘包问题时,分包算法就比较复杂。特别是如图3所示的粘包情况,由于一包数据内容被分在了两个连续的接收包中,处理起来难度较大。实际工程应用中应尽量避免出现粘包现象。

  为了避免粘包现象,可采取以下几种措施。一是对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;二是对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;三是由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。

  以上提到的三种措施,都有其不足之处。第一种编程设置方法虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。第二种方法只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。

  一种比较周全的对策是:接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开。对这种方法我们进行了实验,证明是高效可行的。

三、编程与实现

  1.实现框架

  实验网络通信程序采用TCP/IP协议的socket api编程实现。socket是面向客户机/服务器模型的。TCP实现框架如图4所示。


图4

  2.实验硬件环境:

  服务器:pentium 350 微机

  客户机:pentium 166微机

  网络平台:由10兆共享式hub连接而成的局域网

  3.实验软件环境:

  操作系统:windows 98

  编程语言:visual c++ 5.0

  4.主要线程

  编程采用多线程方式,服务器端共有两个线程:发送数据线程、发送统计显示线程。客户端共有三个线程:接收数据线程、接收预处理粘包线程、接收统计显示线程。其中,发送和接收线程优先级设为thread_priority_time_critical(最高优先级),预处理线程优先级为thread_priority_above_normal(高于普通优先级),显示线程优先级为thread_priority_normal(普通优先级)。

  实验发送数据的数据结构如图5所示:



图5

  5.分包算法

  针对三种不同的粘包现象,分包算法分别采取了相应的解决办法。其基本思路是首先将待处理的接收数据流(长度设为m)强行转换成预定的结构数据形式,并从中取出结构数据长度字段,即图5中的n,而后根据n计算得到第一包数据长度。

  1)若n<m,则表明数据流包含多包数据,从其头部截取n个字节存入临时缓冲区,剩余部分数据依此继续循环处理,直至结束。

  2)若n=m,则表明数据流内容恰好是一完整结构数据,直接将其存入临时缓冲区即可。

  3)若n>m,则表明数据流内容尚不够构成一完整结构数据,需留待与下一包数据合并后再行处理。

  对分包算法具体内容及软件实现有兴趣者,可与作者联系。

四、实验结果分析

  实验结果如下:

  1.在上述实验环境下,当发送方连续发送的若干包数据长度之和小于1500b时,常会出现粘包现象,接收方经预处理线程处理后能正确解开粘在一起的包。若程序中设置了“发送不延迟”:(setsockopt (socket_name,ipproto_tcp,tcp_nodelay,(char *) &on,sizeof on) ,其中on=1),则不存在粘包现象。

  2.当发送数据为每包1kb~2kb的不定长数据时,若发送间隔时间小于10ms,偶尔会出现粘包,接收方经预处理线程处理后能正确解开粘在一起的包。

  3.为测定处理粘包的时间,发送方依次循环发送长度为1.5kb、1.9kb、1.2kb、1.6kb、1.0kb数据,共计1000包。为制造粘包现象,接收线程每次接收前都等待10ms,接收缓冲区设为5000b,结果接收方收到526包数据,其中长度为5000b的有175包。经预处理线程处理可得到1000包正确数据,粘包处理总时间小于1ms。

  实验结果表明,TCP粘包现象确实存在,但可通过接收方的预处理予以解决,而且处理时间非常短(实验中1000包数据总共处理时间不到1ms),几乎不影响应用程序的正常工作
分享到:
评论
1 楼 juren007 2012-10-05  
你好,我最近遇到一个问题就是NIO下面缓冲区的分包,不知如何解决请问可以借鉴一下你的分包算法吗?

相关推荐

    解决TCP网络传输粘包问题

    解决socket TCP网络传输粘包问题

    解决TCP网络传输粘包问题.pdf

    解决TCP网络传输粘包问题.pdf

    C#中TCP粘包问题的解决方法

    主要为大家详细介绍了C#中TCP粘包问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    【QT】自定义协议解决TCP粘包和拆包问题

    本demo模拟了TCP通信中发送端和接收端的行为,并利用序列化和反序列化的思想,自定义协议来解决TCP的粘包和拆包问题。

    TCP网络传输-粘包-问题研究

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

    c#tcp 粘包拆包解决方法,包头加数据长度

    2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。 3、要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。 4、接收数据端的应用层没有及时读取接收缓冲...

    解决TCP网络传输

    解决TCP网络传输,在应用开发过程中,笔者发现基于TCP网络传输的应用程序有时会出现粘包现象(即发送方发送的若干包数据到接收方接收时粘成一包)。

    GOLANG语言实现SOCKET通讯粘包问题解决示例

    GOLANG语言实现SOCKET通讯粘包问题解决示例,对于TCP传输分段,组合无明显界线,造成传输和接收数据包不完整的解决方法!

    C-Byte-Process:处理C语言字节序的简单模块。主要为了解决自己的TCP传输时“粘包”问题

    C字节句柄 处理C语言字节序的简单模块。主要为了解决自己的TCP传输时“粘包”问题

    python粘包问题及socket套接字编程详解

    TCP:适合传输数量大 ,需要建立连接,会出现粘包问题,粘包问题可以解决,确定传入的长度,接收同样长度就可以保证一次性传输完 UDP: 适合传输数据量小,没有粘包,不需要连接,一次性传输,下一次就是新的数据,弊端就是数据...

    python TCP Socket的粘包和分包的处理详解

    概述 在进行TCP Socket开发时,都需要处理数据包粘包和分包的情况。本文详细讲解解决该问题的步骤...虽然socket环境有以上问题,但是TCP传输数据能保证几点: 顺序不变。例如发送方发送hello,接收方也一定顺序接收到h

    C#Socket 封装了Tcp/Udp传输字串、文件、对象

    1.封装了Tcp/Udp传输字串、文件、对象的细节,处理了Tcp粘包问题 2.测试代码设计原始Socket、TcpListener、TcpClient、UdpClient的使用 3.测试代码包括一个可以发送文本消息和发送文件的聊天室 4.设计网络通信、多...

    python socket网络编程之粘包问题详解

    一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用户态...

    解决QTcp上传大文件引起的粘包问题

    1.对于传输不一致导致的粘包问题进行解决 2.自定义协议使收发端以一问一答的模式进行交互 3.以牺牲效率的方式保证数据的稳定和高可靠性 4.避免发送端远超接收端时引发的程序崩溃问题

    socket的粘包处理

    当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API)。TCP/IP传输层有两个并列的协议:TCP和UDP。其中TCP(transport control protocol,传输控制协议)是面向连接的,提供高...

    Qt5写的TCP的C/S模式的文件传输小程序(带界面的局域网通信)(带源码注解)

    TCP的C/S模式的文件传输小程序(带界面的局域网通信), 通过测试,即使是在局域网里面上传大于1G多的文件,也是可以只需要几秒钟, 并且解决了粘包问题, 并且附带源码(外加详细的注释), 生成带界面可执行的...

    Python进阶者笔记(粘包、粘包解决方案)

    文章目录tcp粘包第一种粘包第二种粘包udp粘包解决粘包现象 粘包现象是指发送方发送的若干数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。粘包现象只会在tcp中出现,udp中不会有...

Global site tag (gtag.js) - Google Analytics