`
别惹Java
  • 浏览: 45522 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Java网络编程(五)socket的半包,粘包与分包的问题

 
阅读更多
首先看两个概念:
短连接:
连接->传输数据->关闭连接
   HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。
   也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。

长连接:
连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。
长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。

之所以出现粘包和半包现象,是因为TCP当中,只有流的概念,没有包的概念.

半包
指接受方没有接受到一个完整的包,只接受了部分,这种情况主要是由于TCP为提高传输效率,将一个包分配的足够大,导致接受方并不能一次接受完。(在长连接和短连接中都会出现)。

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

什么时候需要考虑半包的情况?
从备注中我们了解到Socket内部默认的收发缓冲区大小大概是8K,但是我们在实际中往往需要考虑效率问题,重新配置了这个值,来达到系统的最佳状态。
一个实际中的例子:用mina作为服务器端,使用的缓存大小为10k,这里使用的是短连接,所有不用考虑粘包的问题。
问题描述:在并发量比较大的情况下,就会出现一次接受并不能完整的获取所有的数据。
处理方式:
1.通过包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整。
2.指定包的结束标识,这样当我们获取到指定的标识时,说明包获取完整。


什么时候需要考虑粘包的情况?
1.当时短连接的情况下,不用考虑粘包的情况
2.如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
3.如果双方建立连接,需要在连接后一段时间内发送不同结构数据
处理方式:
接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开
注:粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包

备注:

一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,现在一般可允许应用层设置8k(NTFS系)的缓冲区,8k的数据由底层分片,而应用看来只是一次发送。windows的缓冲区经验值是4k,Socket本身分为两种,流(TCP)和数据报(UDP),你的问题针对这两种不同使用而结论不一样。甚至还和你是用阻塞、还是非阻塞Socket来编程有关。
1、通信长度,这个是你自己决定的,没有系统强迫你要发多大的包,实际应该根据需求和网络状况来决定。对于TCP,这个长度可以大点,但要知道,Socket内部默认的收发缓冲区大小大概是8K,你可以用SetSockOpt来改变。但对于UDP,就不要太大,一般在1024至10K。注意一点,你无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。显然,要是一个UDP发包佷大,它被分片后,链路层丢失分片的几率就佷大,你这个UDP包,就佷容易丢失,但是太小又影响效率。最好可以配置这个值,以根据不同的环境来调整到最佳状态。
send()函数返回了实际发送的长度,在网络不断的情况下,它绝不会返回(发送失败的)错误,最多就是返回0。对于TCP你可以字节写一个循环发送。当send函数返回SOCKET_ERROR时,才标志着有错误。但对于UDP,你不要写循环发送,否则将给你的接收带来极大的麻烦。所以UDP需要用SetSockOpt来改变Socket内部Buffer的大小,以能容纳你的发包。明确一点,TCP作为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。
2、关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息,然后再收包数据。一次收齐整个包也可以,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer过小,TCP将返回实际接收的长度,余下的还可以收,而UDP不同的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时,密切注意这点。这些特性就是体现了流和数据包的区别。


参照:http://176170847.iteye.com/blog/819446(Socket粘包问题)
分享到:
评论
1 楼 youjianbo_han_87 2014-03-13  
没有说明,如何处理半包啊。解码的时候,判断解码是否成功?不成功,再次注册读事件?

相关推荐

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

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

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

    通过以上内容,我们可以看到,SuperSocket.ClientEngine.Core提供了强大的工具来处理粘包和半包问题,使得开发者可以专注于业务逻辑,而不是底层网络通信的细节。在实际项目中,根据具体需求选择合适的方法,可以...

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

    在GOLANG中,解决这个问题需要对网络编程原理和GOLANG的网络库有深入理解。本文将详细介绍如何使用GOLANG来解决SOCKET通信中的粘包问题。 首先,理解粘包产生的原因。TCP协议是基于流的,没有明确的数据边界。它会...

    Unity socket 案例包含粘包处理

    "Unity socket案例包含粘包处理"这个标题指向了一个具体的实例,它涉及到在网络通信中如何处理数据包的粘包问题。下面将详细介绍Unity中的Socket通信以及粘包处理的相关知识。 Unity中的Socket通信: Socket是网络...

    Socket编程TCP粘包Demo.zip

    Socket编程在TCP网络通信中是一项基础且重要的技术,而TCP粘包问题则是开发者在实际应用中经常遇到的一个挑战。TCP(传输控制协议)是面向连接的、可靠的传输协议,它在保证数据正确传输的同时,也可能因为其特性...

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

    你可以通过研究这些代码来加深对C# Socket编程的理解,包括异步通信的实现、TCP粘包问题的解决方法,以及如何优化网络通信性能。在实际开发中,结合这些知识,你将能构建出高效、可靠的网络应用程序。

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

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

    winsock socket网络通信_解决粘包问题.zip

    最后,"解决TCP网络传输“粘包”问题TLV SOCKET通信服务器客户机函数流程.doc"很可能详细描述了如何在Winsock中实现TLV协议,以及客户端和服务器之间的通信流程。通常,这会涉及创建套接字、绑定、监听、连接等步骤...

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

    对于初学者而言,掌握如何处理TCP Socket的粘包和分包问题是一个挑战,但也是理解网络编程重要性和实现高效、稳定应用的关键。在Python中,可以利用struct和json模块来方便地处理二进制数据和编码格式化数据。对于...

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

    Socket通信是计算机网络编程中的重要组成部分,主要用于实现进程间的通信,尤其在分布式系统和互联网应用中扮演着核心角色。在TCP/IP协议栈中,Socket接口提供了应用层与传输层之间的接口,使得应用程序能够利用TCP...

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

    总结来说,QT提供的网络编程接口和C++的数据流操作为我们提供了一种有效解决TCP粘包和拆包问题的途径。通过自定义协议,结合序列化和反序列化技术,我们可以在TCP通信中实现可靠的数据交换,确保应用的正常运行。在...

    Netty粘包分包服务器端客户端完整例子

    在使用Netty进行网络通信时,"粘包"和"分包"是两个常见的问题,这两个概念在标题和描述中被提及。 粘包和分包问题通常出现在数据传输过程中。当发送端连续发送多个小包时,接收端可能会一次性接收到这些小包的组合...

    Socket粘包问题终极解决方案-Netty版.docx

    Socket 粘包问题是指在使用 TCP 协议进行网络通讯时,由于 TCP 协议本身没有边界的概念,导致在传输数据时无法确定消息的边界,从而产生粘包和半包问题。本文将详细介绍 Socket 粘包问题的最优解决方案,并提供了...

    粘包和分包及FrameDecoder源码解析.rar

    在计算机网络编程中,尤其是涉及TCP/IP协议时,“粘包”和“分包”是两个重要的概念。这两个术语主要出现在连续发送多个数据包时,由于TCP的流式传输特性,可能会导致数据包边界模糊,从而产生粘包或分包的现象。...

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

    在计算机网络编程中,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。然而,TCP本身并不保证数据包的边界,也就是说,多个小的数据包可能会被合并成一个大的数据包发送,或者一个大的...

    Node.js-NodeJs的TCP中的粘包分包问题的解决方案

    在Node.js中,TCP(传输控制协议)是一个底层网络接口,用于...通过以上策略,开发者可以有效地解决Node.js中的TCP粘包和分包问题,从而实现稳定可靠的网络通信。理解这些机制对于编写高效、健壮的TCP应用至关重要。

    【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案.docx

    ### 游戏开发中TCP粘包与拆包问题解析及解决方案 #### TCP协议基础概述 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在游戏开发中,特别是网络...

    c#网络编程处理网络粘包问题

    在计算机网络编程中,"粘包"问题是一个常见的现象,特别是在TCP协议中。TCP是一种面向连接的、可靠的传输层协议,它为了提高效率,会尽可能地将数据进行批量发送,而不是每次只发送一个数据包。这在某些情况下会导致...

    详细演示如何优雅处理TCP粘包C++源代码 包含完整项目资源确保可顺利编译运行

    本程序使用设计良好的函数,使得应用层不需要考虑网络消息是如何被接受和发送的,重点演示了如何优雅地处理TCP/IP网络数据粘包和丢包的刺手问题,你只要调用相应的函数就可以了。你只需要定义自己的协议头和消息...

Global site tag (gtag.js) - Google Analytics