一端Send一端receive!
包的大小是274872,send的返回值是274884。多了12个字节!
receive端分3次接受!第一次接受到8688字节,第二次接受到136112字节,第三次接受到130084字节。
总共也是274884歌字节!
为什么传送的数据多了12个字节?????
为什么一次send却有3次receive????????????
有时候,连次send的包里的数据会粘连到一起!这有是怎么回事?????怎么避免这种情况??????

解决方案 »

  1.   

    有时候,连次send的包里的数据会粘连到一起!这有是怎么回事?????怎么避免这种情况??????这个肯定是有的,加上启动和停止字符判断。接收数据会放在缓冲区里,同意楼上。
      

  2.   

    一、TCP协议简介    
    TCP是一个面向连接的传输层协议,虽然TCP不属于ISO制定的协议集,但由于其在商业界和工业界的成功应用,它已成为事实上的网络标准,广泛应用于各种网络主机间的通信。    
    作为一个面向连接的传输层协议,TCP的目标是为用户提供可靠的端到端连接,保证信息有序无误的传输。它除了提供基本的数据传输功能外,还为保证可靠性采用了数据编号、校验和计算、数据确认等一系列措施。它对传送的每个数据字节都进行编号,并请求接收方回传确认信息(ACK)。发送方如果在规定的时间内没有收到数据确认,就重传该数据。数据编号使接收方能够处理数据的失序和重复问题。数据误码问题通过在每个传输的数据段中增加校验和予以解决,接收方在接收到数据后检查校验和,若校验和有误,则丢弃该有误码的数据段,并要求发送方重传。流量控制也是保证可靠性的一个重要措施,若无流控,可能会因接收缓冲区溢出而丢失大量数据,导致许多重传,造成网络拥塞恶性循环。TCP采用可变窗口进行流量控制,由接收方控制发送方发送的数据量。    
    TCP为用户提供了高可靠性的网络传输服务,但可靠性保障措施也影响了传输效率。因此,在实际工程应用中,只有关键数据的传输才采用TCP,而普通数据的传输一般采用高效率的UDP。    
     
    二、粘包问题分析与对策    
    TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。    
    出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据(图1所示)。    
    粘包情况有两种,一种是粘在一起的包都是完整的数据包(图1、图2所示),另一种情况是粘在一起的包有不完整的包(图3所示),此处假设用户接收缓冲区长度为m个字节。    
    不是所有的粘包现象都需要处理,若传输的数据为不带结构的连续流数据(如文件传输),则不必把粘连的包分开(简称分包)。但在实际工程应用中,传输的数据一般为带结构的数据,这时就需要做分包处理。    
    在处理定长结构数据的粘包问题时,分包算法比较简单;在处理不定长结构数据的粘包问题时,分包算法就比较复杂。特别是如图3所示的粘包情况,由于一包数据内容被分在了两个连续的接收包中,处理起来难度较大。实际工程应用中应尽量避免出现粘包现象。    
    为了避免粘包现象,可采取以下几种措施。一是对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;二是对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;三是由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。    
    以上提到的三种措施,都有其不足之处。第一种编程设置方法虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。第二种方法只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。    
    一种比较周全的对策是:接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开。对这种方法我们进行了实验,证明是高效可行的。    
     
    三、编程与实现    
    1.实现框架    
    实验网络通信程序采用TCP/IP协议的Socket  API编程实现。Socket是面向客户机/服务器模型的。TCP实现框架如图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.分包算法    
    针对三种不同的粘包现象,分包算法分别采取了相应的解决办法。其基本思路是首先将待处理的接收数据流(长度设为m)强行转换成预定的结构数据形式,并从中取出结构数据长度字段,即图5中的n,而后根据n计算得到第一包数据长度。    
    1)若n2)若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),几乎不影响应用程序的正常工作。
      

  3.   

    kingzai(stevenzhu) 这个试验做的好,收藏
      

  4.   

    粘包现象 确实存在,但有一点TCP是面向字节流的协议比如TCP
    TCP                                  TCP              
    128BYTE,  (第一次send())            |
    64BYTE,   (第二次send())            |
    32BYTE,   (第三次send())            | 
    224BYTE-----------SEND------------recv()(一次收到224BYTE)
    所以如果连续发送较小数据报,TCP一定是重组成一个TCP大包后一次发送
    完毕,所以接收的时候要注意拆包,但有一点是肯定的,不比UDP,它到包的
    次序是有保证的,即recv()为:128+64+32,但UDP是无连接的所以包的顺序肯定
    不保证;
      

  5.   

    估计是楼主具体代码的错误,粘包? 感觉用这个词是太执迷于现象,过份经验化..
    TCP提供是可靠数据流服务,
    所谓'数据流',也就是意味着并不提供发送与接收一一对应的同步服务..
    如果这一点没有悟透,还是会缠绕迷茫于所谓的'粘包'.所谓'可靠',就是TCP协议栈会尽力保证这个数据流数据不丢失不错误,一般网络状况下,
    它可靠度是相当高的,也就是应用层如果编写不犯错误,就不需要应用层再去做数据校验之类工作..'TCP/IP详解'推荐一看.
      

  6.   

    一般是不会出现这个情况的
    我以前刚学的时候有犯过下面这样的错误char buff[128];
    memset(buff,0,sizeof(buff));
    ...
    ... 写数据到buff中
    ...write(socketfd,buff,sizeof(buff)); ....注意这里.不应该是sizeof(buff)的
    应该是buff的具体长度所以你检查一下你的程序,是不是发送的时候指定的长度错误了?
      

  7.   

    看不懂这是什么问题,
    TCP本身就是字节流,根本无所谓什么粘包,因为是流,应该由CLIENT自己来实现读取控制包的大小,
    而且TCP协议为了避免频繁的发送小字节包,
    使用了延迟算法,
    没必要在乎到底有多少直接可读,
    只要判断是否出错,SOCKET——ERROR
    是否没有填满缓冲区就可以了另外从楼主的情况来看,用的是非阻塞SOCKET调用,
    采用非阻塞,本身确实比较难处理,
    因为无法判断什么时间发送完毕,发送多少次,每次多少字节,这全由TCP层来处理,
    程序只能知道什么时间发送完成了,
    因此就出现了CLIENT调用了N次的情况
      

  8.   

    TCP的发送缓冲有个作用,如果接收方没有确认收到数据,那是不会从缓冲中删除的。
    所以说应该是你的程序问题,并不是什么粘包的问题。
      

  9.   

    那么UDP实时传送时应怎么处理呢? 我以前做的一个视频传输是发送时延时十毫秒来解决粘包现象的。
      

  10.   

    我前几天调试发送短信的程序时候也遇到了这个问题.我用一个网络监视工具检测到发送到短信网关的前后2条短信经常粘在一起,而且短信网关那边不能正确的分包,我只好在客户端这边每发送完一个包sleep 100毫秒,现在问题是没有了,但解决方法并不合适.
    看到前面那片文章说可以用push的方法,那么如果push完了服务其那边仍旧没有给客户端ack怎么办?
      

  11.   

    UDP不存在粘包的现象,它是有边界的,接收方调用一次recvfrom保证只会收到一个udp包(和发送方发来的一模一样,另外如果这个待接收的包长度如果超过你提供的缓冲区长度,那么底层会简单的丢弃这个包,导致你收不到数据),不象TCP基于流
      

  12.   

    TCP方式通信都要想这个问题的.由于它是一个可靠的,所以它的数据包不会丢的也不会多.它是以流的方式传输的,所以它没有边界.如果你使用TCP方式通信,就要在你通信的时候,要定义一下你有通信的数据包的基本的一个格式.在接收的时候按格式解析出来.这样就不会有问题了.你一下子发这样大的内存块,也没有什么格式限制,一定有问题的.
      

  13.   

    kingzai(stevenzhu) 写的真的好!!
      

  14.   

    我比较同意danscort和haungrui的说法,另外TCP_NODELAY Socket Option不是可以关闭Nagle algorithm 吗?这样不能解决所谓的"粘包"问题吗?