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

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

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

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

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

什么时候需要考虑粘包的情况? 
1.当是短连接的情况下,不用考虑粘包的情况 
2.如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包 
3.如果双方建立连接,需要在连接后一段时间内发送不同结构数据

下面看个具体事例
假设我们连续调用两次send分别发送两段数据data1和data2,在接收端有以下几种接收情况(当然不止这几种情况,这里只列出了有代表性的情况).
A.先接收到data1,然后接收到data2.
B.先接收到data1的部分数据,然后接收到data1余下的部分以及data2的全部.
C.先接收到了data1的全部数据和data2的部分数据,然后接收到了data2的余下的数据.
D.一次性接收到了data1和data2的全部数据.

对于A这种情况正是我们需要的,不再做讨论.对于B,C,D的情况就是大家经常说的"粘包",同时BC中也有半包的问题,就需要我们把接收到的数据进行拆包,拆成一个个独立的数据包.为了拆包就必须在发送端进行封包.

另:对于UDP来说就不存在拆包的问题,因为UDP是个"数据包"协议,也就是两段数据间是有界限的,在接收端要么接收不到数据要么就是接收一个完整的一段数据,不会少接收也不会多接收.而TCP当中,只有流的概念,没有包的概念.

二.为什么会出现B.C.D的情况.
"粘包"可发生在发送端也可发生在接收端.
1.由Nagle算法造成的发送端的粘包:Nagle算法是一种改善网络传输效率的算法.简单的说,当我们提交一段数据给TCP发送时,TCP并不立刻发送此段数据,而是等待一小段时间,看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去.这是对Nagle算法一个简单的解释,详细的请看相关书籍.象C和D的情况就有可能是Nagle算法造成的.
2.接收端接收不及时造成的接收端粘包:TCP会把接收到的数据存在自己的缓冲区中,然后通知应用层取数据.当应用层由于某些原因不能及时的把TCP的数据取出来,就会造成TCP缓冲区中存放了几段数据.

针对粘包和半包的解决方案
1.封包:通过包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整。 
2.指定包的结束标识,这样当我们获取到指定的标识时,说明包获取完整。

封包就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容了(以后讲过滤非法包时封包会加入"包尾"内容).包头其实上是个大小固定的结构体,其中有个结构体成员变量表示包体的长度,这是个很重要的变量,其他的结构体成员可根据需要自己定义.根据包头长度固定以及包头中含有包体长度的变量就能正确的拆分出一个完整的数据包.
    对于拆包目前我最常用的是以下两种方式.
    1.动态缓冲区暂存方式.之所以说缓冲区是动态的是因为当需要缓冲的数据长度超出缓冲区的长度时会增大缓冲区长度.
    大概过程描述如下:
    A,为每一个连接动态分配一个缓冲区,同时把此缓冲区和SOCKET关联,常用的是通过结构体关联.
    B,当接收到数据时首先把此段数据存放在缓冲区中.
    C,判断缓存区中的数据长度是否够一个包头的长度,如不够,则不进行拆包操作.
    D,根据包头数据解析出里面代表包体长度的变量.
    E,判断缓存区中除包头外的数据长度是否够一个包体的长度,如不够,则不进行拆包操作.
    F,取出整个数据包.这里的"取"的意思是不光从缓冲区中拷贝出数据包,而且要把此数据包从缓存区中删除掉.删除的办法就是把此包后面的数据移动到缓冲区的起始地址.

这种方法有两个缺点.1.为每个连接动态分配一个缓冲区增大了内存的使用.2.有三个地方需要拷贝数据,一个地方是把数据存放在缓冲区,一个地方是把完整的数据包从缓冲区取出来,一个地方是把数据包从缓冲区中删除.第二种拆包的方法会解决和完善这些缺点.

前面提到过这种方法的缺点.下面给出一个改进办法, 即采用环形缓冲.但是这种改进方法还是不能解决第一个缺点以及第一个数据拷贝,只能解决第三个地方的数据拷贝(这个地方是拷贝数据最多的地方).第2种拆包方式会解决这两个问题.
环形缓冲实现方案是定义两个指针,分别指向有效数据的头和尾.在存放数据和删除数据时只是进行头尾指针的移动.

2.利用底层的缓冲区来进行拆包
由于TCP也维护了一个缓冲区,所以我们完全可以利用TCP的缓冲区来缓存我们的数据,这样一来就不需要为每一个连接分配一个缓冲区了.另一方面我们知道recv或者wsarecv都有一个参数,用来表示我们要接收多长长度的数据.利用这两个条件我们就可以对第一种方法进行优化.
     对于阻塞SOCKET来说,我们可以利用一个循环来接收包头长度的数据,然后解析出代表包体长度的那个变量,再用一个循环来接收包体长度的数据.

借鉴于:https://blog.csdn.net/zhangxinrun/article/details/6721495

https://blog.csdn.net/sunmenggmail/article/details/38952131

http之 半包 粘包相关推荐

  1. netty 客户端断开 异常处理_netty案例,netty4.1基础入门篇八《NettyClient半包粘包处理》发数据方式》...

    小傅哥 | https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获.专注于原创专题案例编写,目前已完成的专题有:Netty4.x实战专题案例.用Java实现JVM.基于Ja ...

  2. java nio解决半包 粘包问题

    java nio解决半包 粘包问题 NIO socket是非阻塞的通讯模式,与IO阻塞式的通讯不同点在于NIO的数据要通过channel放到一个缓存池ByteBuffer中,然后再从这个缓存池中读出数 ...

  3. 使用包定长FixedLengthFrameDecoder解决半包粘包

    四.使用包定长FixedLengthFrameDecoder解决半包粘包 4.1 试验 由于客户端发给服务器端的是hello server,im a client字符串,该字符串占用24字节,所以在服 ...

  4. netty半包粘包 处理_老王:Netty到底是个什么鬼?有没有简单的理解方式?

    前语:不要为了读文章而读文章,一定要带着问题来读文章,勤思考. 作者:lyowish    来源:http://1t.click/7RY # 从HTTP说起 有了Netty,你可以实现自己的HTTP服 ...

  5. netty半包粘包 处理_Java NIO 框架 Netty 之美:粘包与半包问题

    一.前言 Netty 是一个可以快速开发网络应用程序的 NIO 框架,它大大简化了 TCP 或者 UDP 服务器的网络编程.Netty 的简易和快速开发并不意味着由它开发的程序将失去可维护性或者存在性 ...

  6. 坑人无数的俩货:半包和粘包

    顾名思义,就是收到了半个包,这个时候不足以组成一个应用层的包.就像你要对你喜欢的人说"我喜欢你",但是因为喝水咽着了,第一次只说了"我"字,第二次说了个&quo ...

  7. UDP和TCP 的半包、粘包、拆包

    ###简介 tcp是以流式发送数据的,数据之间无明显界限,只能人为的划分数据包的边界 在发送过程中 会因为缓冲区太小在传输超大包时 出现"半包" 会因为接收端消费速度太慢,导致数据 ...

  8. websocket是否需要处理粘包半包问题分析

    结论: ​ 不需要. 背景: ​ 公司通信涉及到websocket相关,我们都知道websocket是基于tcp的,而tcp是面向字节流的,是需要处理粘包半包问题的.那么websocket是否需要处理 ...

  9. 自定义Udp/Tcp协议,通信协议Socket/WebSocket,IM粘包、分包解决等(2),ProtocolBuffer

    > 自定义Udp/Tcp协议/通信协议(Java/C):自定义构建和解析IM协议消息:IM自定义UDP通信协议   类似于网络通信中的TCPIP协议一般,比较可靠的通信协议往往包含有以下几个组成 ...

最新文章

  1. ThinkPHP5.0中Redis的使用和封装(原创)
  2. WL 2009 professional【已解决】谢谢nooby跟海风
  3. DL框架之AutoKeras框架:深度学习框架AutoKeras框架的简介、特点、安装、使用方法详细攻略
  4. c语言如何判断密码不同字符,C语言从文本文档读取字符串(用户名和密码验证)...
  5. Android零基础入门第31节:几乎不用但要了解的AbsoluteLayout绝对布局
  6. 全方位了解超宽带信号高速采集记录回放系统
  7. 游戏主播这个行为终于有人治了!腾讯下“禁令”
  8. 在SQL Server查询分析器里查询Excel文件数据
  9. 左列定宽,右列自适应
  10. python的dict()字典数据类型的方法详解以及案例使用
  11. 百炼-2701:与7无关的数
  12. 文件源路径太长无法删除
  13. 头歌c语言答案循环结构,C语言的“汤头歌”
  14. 如何在doc下运行java程序及打包成.jar格式的Java程序
  15. origin画图初步入门
  16. 在python编译器中调用JAVA程序——JPype使用总结
  17. FPGA中CDC问题
  18. HDU 1873 - 看病要排队 ← 优先队列
  19. CSS线性渐变和径向渐变详解
  20. 关于airdroid免root操作

热门文章

  1. 目标跟踪测试工具OTB使用教程
  2. 互为质数的实际意义举例一
  3. Java中匿名子类 的 匿名对象、匿名子类 的 非匿名对象、非匿名类 的 匿名对象、非匿名类 的 非匿名对象
  4. 如何翻译音频?音频翻译器有哪些?
  5. IPV6网络发展过程
  6. Bootstrap+Jquery的日历效果实现
  7. 基于linux的openwrt基础教程图解
  8. Python--猜水果游戏
  9. 2021 mathematical modeling national competition question B
  10. k8s系列08-负载均衡器之PureLB