为什么编解码

发表时间:2017-09-21 16:17:01 浏览量( 23 ) 留言数( 0 )

学习目标:

1、了解粘包、拆包等问题

2、了解Netty的编解码


学习过程:

一、TCP的粘包、拆包问题

    TCP并不能了解上层的业务数据,数据在传输过程中是编码后传输的,如果不加以处理事实上并不知道怎样才算是一条完整的数据,在传输过程会发生粘包、拆包等问题。我们来看一下下面的一些例子:

    现在假设客户端向服务端连续发送了两个数据包,用packet1和packet2来表示,那么服务端收到的数据可以分为三种,现列举如下:

    第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内。normal

attcontent/67d0f2d0-9d28-45f9-8b2c-1ec76118e54a.png

    第二种情况,接收端只收到一个数据包,由于TCP是不会出现丢包的,所以这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。one

attcontent/4da95d23-e943-480f-babe-bb36923e737d.png

    第三种情况,这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。

attcontent/71d3d92b-424e-4eb7-bd61-feb559bca534.png

二、Netty的编解码器

    对于粘包、拆包的问题,Netty提供了强大的编解码方案,让我们可以轻松的解决这些问题。netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装重用。

    在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。编解码器由两部分组成:编码器、解码器。 

    编码器:将消息对象转成字节或其他序列形式在网络上传输。

    解码器:负责将消息从字节或其他序列形式转成指定的消息对象; 

    编码器和解码器的结构很简单,消息被编码后解码后会自动通过ReferenceCountUtil.release(message)释放,如果不想释放消息可以使用ReferenceCountUtil.retain(message),这将会使引用数量增加而没有消息发布,大多数时候不需要这么做。

    在昨天的例子我们已经自己定义和使用了编解码器了,但是在实际开发中我们需要传递的数据更多、更复杂,Netty帮助我们定义了一些比较常用的解码器,比较常见的有下面:

  • LineBasedFrameDecoder解码器

    LineBasedFrameDecoder是回车换行解码器,如果用户发送的消息以回车换行符作为消息结束的标识,则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码,只需要在初始化Netty服务端或者客户端时将LineBasedFrameDecoder正确的添加到ChannelPipeline中即可,不需要自己重新实现一套换行解码器。

  • DelimiterBasedFrameDecoder分隔符解码器

    DelimiterBasedFrameDecoder分隔符解码器,用户可以指定消息结束的分隔符,它可以自动完成以分隔符作为码流结束标识的消息的解码。回车换行解码器实际上是一种特殊的DelimiterBasedFrameDecoder解码器。

  • FixedLengthFrameDecoder固定长度解码器

    FixedLengthFrameDecoder固定长度解码器,它能按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包等问题。利用FixedLengthFrameDecoder解码,无论一次性接收到多少的数据,他都会按照构造函数中设置的长度进行解码;如果是半包消息,FixedLengthFrameDecoder会缓存半包消息并等待下一个包,到达后进行拼包,直到读取完整的包。