`

Socket/TCP粘包、多包和少包, 断包

    博客分类:
  • java
 
阅读更多
为什么TCP 会粘包

  前几天,调试mina的TCP通信, 第一个协议包解析正常,第二个数据包不完整。为什么会这样吗,我们用mina这样通信框架,还会出现这种问题? 带者问题,我们先分析一下问题。
  提到通信, 我们面临都通信协议,数据协议的选择。 通信协议我们可选择TCP/UDP:

    TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。

    UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。

由于TCP无消息保护边界, 需要在消息接收端处理消息边界问题。也就是为什么我们以前使用UDP没有此问题。 反而使用TCP后,出现少包的现象。
粘包的分析
上面说了原理,但可能有人使用TCP通信会出现多包/少包,而一些人不会。那么我们具体分析一下,少包,多包的情况。

    正常情况,发送及时每消息发送,接收也不繁忙,及时处理掉消息。像UDP一样.
    发送粘包,多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包. 这种情况和客户端处理繁忙,接收缓存区积压,用户一次从接收缓存区多个数据包的接收端处理一样。
    发送粘包或接收缓存区积压,但用户缓冲区大于接收缓存区数据包总大小。此时需要考虑处理一次处理多数据包的情况,但每个数据包都是完整的。
    发送粘包或接收缓存区积压, 用户缓存区是数据包大小的整数倍。 此时需要考虑处理一次处理多数据包的情况,但每个数据包都是完整的。
    发送粘包或接收缓存区积压, 用户缓存区不是数据包大小的整数倍。 此时需要考虑处理一次处理多数据包的情况,同时也需要考虑数据包不完整。

  我们的情况就属于最后一种,发生了数据包不完整的情况。
啰嗦了这么多,总结 一下, 就两种情况下会发生粘包。

    发送端需要等缓冲区满才发送出去,造成粘包
    接收方不及时接收缓冲区的包,造成多个包接收

如何应对
先卖个关子, 不是所有的粘包都需要处理。 我们先列举一下,免得在编码过程中,因为知道了粘包的情况下,都处理粘包。

    连续的数据流不需要处理。如一个在线视频,它是一个连续不断的流, 不需要考虑分包。
    每发一个消息,建一次连接的情况。
    发送端使用了TCP强制数据立即传送的操作指令push。
    UDP, 前面已说明白了。在这在强调一下,UDP不需要处理,免的忘记了。

    如果用socket编写编程的话, 我就不多说我, 可参考下面的资料:
    Grizzly: http://grizzly.java.net/nonav/docs/docbkx2.0/html/coreframework-samples.html User Guide 第二章的样例:解析收到的消息。
    xSocket:http://xsocket.sourceforge.net/core/tutorial/V2/TutorialCore.htm 第 18 节。
    Netty: http://netty.io/docs/3.2.6.Final/api/org/jboss/netty/handler/codec/frame/FrameDecoder.html FrameDecoder 的 API 文档。Netty 抽象了一个“消息桢解码器”的类来处理这些。
    Mina 2:http://mina.apache.org/chapter-11-codec-filter.html
    Mina 2:如果En文不好的话, 可参考http://freemart.iteye.com/blog/836654。  它在判断包是否完整时,有个小缺陷,它没使用IOBuffer的prefixedDataAvailable。但注释写的比较好。

把官网上的代码,也在这展示一下。

public class ImageResponseDecoder extends CumulativeProtocolDecoder {

   /**
     * 返回值的解释:
     * 1、false, 继续接收下一批数据,有两种情形,如缓冲区数据刚刚就是一个完整消息,或不够一条消息时。如果不够一条消息,那么会将下一批数据和剩余消息进行合并
     * 2、true, 当缓冲区的消息多于一条消息时,剩余消息会再会推送至doDecode
   */

    protected  boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)throws Exception {
       //发送数据时,头四个字节记录了消息的长度。 此方法会读四个字节,并和实现流长度对比。返回前,将流reset.
    if (in.prefixedDataAvailable(4)) {
       int length = in.getInt();
       byte [] bytes = newbyte[length];
       in.get(bytes);
       ByteArrayInputStream bais =new ByteArrayInputStream(bytes);
       BufferedImage image = ImageIO.read(bais);
       out.write(image);
        return true;//如果读取内容后还粘了包,系统会自动处理。
   }else{
       returnfalse;//继续接收数据,以待数据完整
    } 
  }
}

    再总结一下处理流程: 就发送数据时,包开始写入消息长度n, 当接收到的缓存区数据m,各处理流程如下:
      1)若n<m,则表明数据流包含多包数据,从其头部截取n个字节存入临时缓冲区,剩余部分数据依此继续循环处理,直至结束。或n>m
      2)若n=m,则表明数据流内容恰好是一完整结构数据,直接将其存入临时缓冲区即可。
      3)若n >m,则表明数据流内容尚不够构成一完整结构数据,需留待与下一包数据合并后再行处理。

参考
http://blog.csdn.net/binghuazh/article/details/4222516
http://www.cnblogs.com/alon/archive/2009/04/16/1437600.html
http://hi.baidu.com/chongerfeia/blog/item/b1e572f631dd7e28bd310965.html
http://freemart.iteye.com/blog/836654
http://blianchen.blog.163.com/blog/static/1310562992010101891522100/
http://mina.apache.org/chapter-11-codec-filter.html
分享到:
评论

相关推荐

    SuperSocket.ClientEngine.Core socket 客户端处理粘包半包

    本篇文章将深入探讨如何在使用SuperSocket.ClientEngine.Core库时,处理客户端的粘包和半包问题。 粘包和半包是网络通信中的常见问题,主要出现在TCP协议中。由于TCP为了提高传输效率,会将多个小的数据包合并成一...

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

    TCP粘包是指发送方发送的多个数据包在接收方接收时被合并成一个大包,使得接收方无法正确区分各个独立的数据包。这种问题通常是由于TCP的优化策略,例如Nagle算法,以及接收方的处理方式导致的。 TCP粘包的产生主要...

    Socket编程TCP粘包Demo.zip

    本示例通过"Socket编程TCP粘包Demo.zip"提供了客户端和服务器端的代码,帮助我们更直观地理解这一现象。 首先,TCP粘包是指在接收方收到的数据边界不清晰,多个小的数据包被合并成一个大的数据包进行接收的情况。这...

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

    在某些需要精确控制数据传输的应用中,如游戏、实时通信等,解决TCP粘包和拆包问题是至关重要的。QT是一个跨平台的C++图形用户界面应用程序开发框架,它提供了丰富的网络编程接口,可以用来处理这个问题。 本文将...

    unity实现Socket通讯(内含tcp粘包/拆包解决)

    Unity中的Socket通信是游戏开发中实现网络交互的重要技术,它基于C#语言,允许服务器和...解决TCP粘包/拆包问题,可以确保数据正确无误地传输。理解并熟练掌握这些知识点,对于开发网络游戏或实时交互应用至关重要。

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

    发生TCP粘包或拆包有很多原因,现列出常见的几点,可能不全面,欢迎补充, 1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。 2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。 3、...

    Socket编程TCP粘包问题及解决方案.docx

    ### Socket编程TCP粘包问题及解决方案 #### 一、TCP粘包问题概述 TCP作为一种可靠的面向连接的传输层协议,提供了基于字节流的服务。在TCP传输过程中,发送方发送的数据被视为连续不断的字节流,而不是离散的消息...

    C#TCP\Socket粘包处理(加长度头)

    1. **理解TCP粘包** - TCP是一个字节流服务,没有天然的数据包边界。 - 粘包是由于TCP的流量控制和拥塞控制可能导致的数据交错。 - 数据可能会在发送端被缓冲,然后一次性发送出去,或者在接收端被合并。 2. **...

    C#实现Socket编程 (异步通讯,解决Tcp粘包)第三阶段

    本文将深入探讨如何使用C#语言来实现Socket编程,特别是在处理异步通信和解决TCP粘包问题的第三阶段。C#提供了丰富的类库支持网络编程,使得开发者能够方便地构建基于TCP/IP的客户端和服务器应用。 首先,让我们...

    Socket通信,通过异步,解决粘包问题

    所谓“粘包”,是指在网络传输过程中,由于TCP协议的流式特性,多个数据包可能会被合并成一个大的数据包进行传输,或者一个数据包被分割成多个小的数据包分别发送,导致接收方无法正确区分每个数据包的边界,从而...

    Unity + Socket + Protobuff+异步+粘包拆包断包_V2

    V2"聚焦于解决在使用Socket进行网络通信时常见的问题,如粘包、拆包、断包以及断线重连等,同时结合了Protocol Buffers(Protobuff)这一高效的数据序列化协议,以提高数据传输的效率和稳定性。 首先,让我们深入...

    socket tcp如何防止多次send的包被合成一个包(粘包)发送.zip

    标题"socket tcp如何防止多次send的包被合成一个包(粘包)发送"主要关注的是如何避免这种粘包现象。以下是一些防止TCP粘包的方法: 1. **设置TCP_NODELAY选项**: - 文件"2使用TCP_NODELAY选项,告诉内核尽快将该...

    Golang TCP粘包拆包问题的解决方法

    ### Golang TCP粘包拆包问题的解决方法 #### 一、引言 在使用Go语言进行网络编程时,特别是TCP编程过程中,经常会遇到所谓的“粘包”与“拆包”问题。这些问题的发生通常会影响到数据的正确性以及系统的稳定性。...

    C# TCP粘包解决

    总结起来,解决C#中的TCP粘包问题需要理解TCP协议的工作原理,合理设计数据包格式,有效管理接收缓冲区,利用同步机制和异步编程技术,以及考虑是否使用第三方库来简化开发。通过深入研究提供的代码示例,可以进一步...

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

    在TCP/IP通信中,"粘包...总之,解决GOLANG中的SOCKET通信粘包问题,关键在于定义清晰的协议格式,并在客户端和服务器端正确地打包和解包数据。通过这种方式,即使在TCP的流式传输中,也能确保数据的完整性和准确性。

    C#解决socket粘包问题,通信提供了一个自定义通信协议类MsgProtol,该类封装了打包和解包方法,可以解决分包和粘包问题

    C#解决socket通信过程中粘包分包问题,本项目是一个只有6个C#代码文件的开源小工程,用来学习基于TCP的套接字通信包,可以自定义通信协议,处理分包和粘包,内置一个服务端和客户端的套接字程序,也有测试代码和对应...

    Unity socket 案例包含粘包处理

    在TCP协议中,由于其流式传输的特点,可能会出现多个数据包被合并成一个大的数据包发送,或者一个数据包被拆分成多个小的数据包发送,这就是所谓的“粘包”或“拆包”问题。在Unity中,如果不对数据进行适当的分包和...

    Boostasio异步TCP通讯及tcp粘包解包解决方案.doc

    TCP粘包解包是指在数据传输过程中,接收方可能会收到多个数据包,并将其合并成一个完整的数据包。这需要在发送方和接收方之间进行协调。 解决 TCP 粘包解包问题的方法有多种,常见的方法包括: 1. 使用固定长度的...

Global site tag (gtag.js) - Google Analytics