TCP粘包和拆包

这个东西在网络编程中老生常谈的一个问题了,网上这个相关的知识非常之多。多到我关于这方便多打一个字,都是重复的那种,哈哈哈。还是以理解为主。

TCP/IP协议分层模型

网络到底分几层,有分七层的,有分四层的,也有分五层的。不钻牛角尖哈,大致看一下。

大学教科书中有说分成7层,也有说分成4层的,笔者觉得4层更合适一些,像七层中的第5、6层完全不是必须的,就算有也是各自制定协议,而制定协议的人基本不会去考虑第5层叫会话层第6层叫表示层,在私有应用层协议中,更多的是会私定一个握手互信协议,以表示通讯双方是互信的

网络通信协议分层图

应用层

  • 你想用java写一个网络程序,你写的这个程序就是应用层
  • 所以QQ、微信、以及你正在使用的浏览器,都是应用层

这层就是我们主要关注的,我们写的绝大部分代码写的也就是这层。

传输层

  • 传输层要么走TCP协议,要么走UDP协议,没有第三种协议。
  • TCP协议的通信双方,需要知道彼此都在家呆着,且由客户端主动发起连接。
  • UDP协议,客户端知道服务器家住在哪,但并不知道服务器在不在家,扔条消息去服务器家,如果服务器不在家这条消息就被丢了。

其他的

太过底层的我们接触不到,编程语言已经封装好了。再或者可能操作系统也给你封装好了。用就行了。

粘包和拆包是怎么产生的

归根结底,就是TCP是个“流”协议,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。这样说可能不太理解,随便搜索一下一大堆,看几篇就就理解了。

如何解决

上面说了,是一个没有界限一串数据,那么我们传输数据的时候加个界限不就好了。加界限的方式也就是解决方案,有直接加分隔符的,有规定每次接收字节长度的(不怎么常用),还有就是每次发报文,在报文的头部几个字节,和接收方说,我要发多少字节数据的(常用!!)。

netty解决方案:关注一下这两个类即可。LengthFieldBasedFrameDecoder,LengthFieldPrepender这两个类采用了在报文头部增加表示报文长度的数据。

TIO里,官网上示例的编解码解码器已经做了粘包和拆包的处理。处理方式同上。之前写的那篇博文可以看一下,就是里面的编解码代码。

最后

多多理解,理解之后哪怕让你写一个简单的拆包粘包处理方案你也能写出来,但是,在框架的有的情况下,不建议自己去写,因为这个粘包和半包处理在多线程中处理起来,有点麻烦,需要拼接数据,如果第一次发了一半,第二次怎么处理,如果收多了,又怎么处理,并不简单。现成的轮子就好好用。😃😃

封面

快乐工作 早日退休


TCP粘包和拆包
https://wangijun.com/2022/08/08/net-04/
作者
无良芳
发布于
2022年8月8日
许可协议