2023-09-13
原文作者:https://blog.csdn.net/wangwei19871103/category_9681495_2.html 原文地址: https://blog.csdn.net/wangwei19871103/article/details/104519909

编解码器简介

我们来说说编解码器吧,简单来说就是把一堆数据变成另一堆,但是也变回来,在我们netty里,大多数就是从字节数组变成消息对象,或者一种类型的对象变成另一种。但是在网络传输中,编解码器就不是那么简单了,因为网络环境复杂,涉及很多通信机制,会使得你收到的数据不一定就是完整的数据,导致直接解码出错,很常见的就是TCP的半包粘包等问题,因为TCP的数据是流式传传输的,他压根不管流出去的数据有几个消息,他只管自己传输层的问题就行,至于这堆字节是几个消息组成的那是应用层的事,所以我们需要解决粘包半包问题。

粘包半包问题

什么是粘包半包问题呢,简单来说就是我接受到了一个消息,但是后面好像带了其他的消息,这个就是粘包,半包就是我只接受到了一般的消息。举个例子,我要发短信给别人,我连续发了2条消息。第一条是“你好在么”,第二条是“我有事请教你”,我当然希望能一条条到那边,但是TCP协议不管,别人接受到的可能会出现这几种情况:

  • 你好在么,我有事请教你 --正常
  • 你好,在么我有事请教你 --半包 粘包
  • 你好在么我有,事请教你 --粘包 半包
  • 你好在么我有事请教你 --粘包

第一种情况是好的,其他三种都是有问题的。有人会说了应该还有一种吧,比如
你请教你好在么我有事,也就是消息内部的顺序都错乱了,这个不会出现,因为你发送的时候是顺序放到缓冲区里的,也是顺序取的,不然处理起来就难了,而且也没必要乱着发呀。当然在发送的时候因为MTU限制,可能会把包成好几个小包发,而且到达对端的顺序也可能不一样,但是他们都是有序号的,对端收集起来会按序号排列好,然后给接受缓冲区。
我再用图示来说明下问题吧:

202309132206590711.png

如何解决粘包半包问题

基本的思路就下面三个,前面两个不是很好的办法,租后一个比较常用的。

  • 固定长度
  • 分隔符分割
  • 基于可变长度

基于可变长度

基本的思想就是我在消息最前面的几个字节加上消息体的长度,或者是总共消息的大小,反正只要你能解析出前几个字节表示的数,你就能知道后面还有多少个字节是属于这个消息的。当然具体的问题看到比较复杂,比如你需要有个字节的缓存,因为你可能受到了消息某个消息的一部分,还需要接受另一部分,所以要保存起来。比如这种,消息前4个字节是消息体的长度,这样你读完前4个之后,你就知道还要读多少个就可以拼成一个完整的消息啦,不过这种还是要约定的,比如约定前面4个字节是消息体长度:

202309132206598582.png

netty的编解码器

netty提供了一个抽象类ByteToMessageDecoder来完成解码器的基本流程,当然也给了很多子类实现,大多数我们需要的都有了,比如固定长度,分割符,行分割,基于长度的等等。
同理还有编码的MessageToByteEncoder。其实他们都是Handler,只要在入站或者出站的时候先进过他们,能有完整的消息了,再往后传递,这样后续的处理器接受的肯定是完整的包了,不完整的不会接受到。

接下去准备讲下ByteToMessageDecoder解码器做了些什么。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

阅读全文