Netty入站和出站的时候一定要对message消息进行解码和编码操作

Netty入站和出站的时候一定要对message消息进行解码和编码操作

应用程序往网络冲刷的数据不进行编码处理就不能成功冲刷

Netty入站和出站的时候一定要对message消息进行解码和编码操作,要确保消息从应用程序流入网络的时候被编码成了二进制,以及消息从网络流入应用程序的时候要确保二进制被解码成了正确的类型。

因为我们的数据在网络中一定是通过二进制的形式传输的,因此我们如果仅仅冲刷数据,比如说冲刷一个字符串,那么这个数据是不能被冲刷到网络中的,会冲刷失败,后续我们服务器端是读取不到的。
比如说假如我们的客户端没有写编解码处理器,如下图:
在这里插入图片描述
再看下客户端往网络中冲刷的数据,如下图:
在这里插入图片描述

因为客户端往网络中冲刷数据的时候没有进行二进制编码,因此客户端是不能成功的把数据冲刷到网络中。那么也就是说,在我们服务端通过ChannelHandler处理器的channelRead0方法读取数据的时候就读取不到,如下图:
在这里插入图片描述
上面的这个方法就进不来。

既便客户端冲刷数据的时候使用了编码处理器,如果服务器解码的时候解码生成的对象类型和channelRead0方法里的对象类型不一致,那么channelRead0方法也进不来

比如现在给客户端加上一个编码处理器如下图:
在这里插入图片描述
然后编码处理器是把String字符串类型转换为二进制 如下图:
在这里插入图片描述
这样能保证客户端的字符串数据能够成功的冲刷到网络中,因为冲刷之前客户端把数据转换成了二进制的形式;
然后再在服务器端加一个解码处理器,这个处理器可以把从网络中读取的二进制数据转换成字符串数据,如下图:
在这里插入图片描述
在这里插入图片描述
按道理来说,我在服务器端已经把网络中读取来的数据解码成了字符串,所以应该可以成功的被责任链中的后续节点ChannelHandler中的处理器的channelRead0方法读取到了,但是真的未必,如果解码处理器的解码对象类型,和channelRead0中的对象类型不一致的话,比如服务器的解码处理器是把网络中的二进制数据转换成了String类型,但是此时后续责任链中的ChannelHandler处理器中的channelRead0方法的参数对象却是Long类型,二者数据类型不一致,那么服务器解码处理器处理之后并不能够传送给下一个ChannelHandler节点处理,那么也就进入不到channelRead0方法了。看下参数类型为Long的channelRead0方法如下图:
在这里插入图片描述
现在一共有两种处理方式,但底层思想其实是一致的,就是要确保解码之后生成的对象类型和我们下一个ChannelHandler节点的channelRead0方法中的参数类型要一直

  • 一种方法是把解码处理器生成的解码对象从String改成Long;
  • 另外一种方法是把channelRead0方法中的参数对象从Long改为String;

以后的写作规范

规范1:责任链头部写上编解码处理器
因此以后在应用程序当中,不管是在客户端应用程序,还是在服务端应用程序,写处理器的时候,在责任链的头部首先要写上编码处理器和解码处理器,然后再写业务相关的ChannelHandler处理器,如下图:
在这里插入图片描述
在这里插入图片描述
这是一种保证数据能够成功冲刷到网络中的一种规范。如果不写编码处理器,但是你能够保证数据以二进制的方式冲刷到网络中也可以,比如通过下面这种方式,如下图:
在这里插入图片描述
上面的Unpooled.copiedBuffer方法可以把我们的数据转变成网络能接受的二进制数据格式。

虽然说用第二种方式也可以,但是我们还是推荐你使用在应用程序的ChannelPipeline中的责任链的头部加上编码处理器。为什么呢?因为这样可以形成一种操作规范,后期比较方便理解,也比较方便开发。

规范二:确保解码处理器解码生成的对象和后续的入站处理器InboundHandler的channelRead0方法中的参数对象一致
因为虽然你的网络二进制数据被成功解码成了某一个对象,但是如果想要让你的数据能够被后续的ChannelHandler处理,那么必须保证解码之后的生成对象的类型和后续的ChannelHandler处理器中的channelRead0方法中的参数类型一致,否则你的数据就不会流转到后面的ChannelHandler处理。也就无法进行业务处理了。

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Netty框架提供了很多编码器和解码器,但有时候我们需要自定义编码器和解码器,以满足特定的业务需求。在Netty中,自定义编码器和解码器非常简单,只需要继承ByteToMessageDecoder或MessageToByteEncoder,并实现其中的抽象方法即可。 以下是一个自定义编码器的示例代码: ```java public class MyEncoder extends MessageToByteEncoder<MyMessage> { @Override protected void encode(ChannelHandlerContext ctx, MyMessage msg, ByteBuf out) throws Exception { byte[] data = msg.getData(); out.writeInt(data.length); out.writeBytes(data); } } ``` 在这个示例中,我们定义了一个名为MyEncoder的编码器,它继承自MessageToByteEncoder,并实现了encode方法。在encode方法中,我们首先获取消息的数据,然后将消息的数据长度写入到ByteBuf中,最后将消息的数据写入到ByteBuf中。 以下是一个自定义解码器的示例代码: ```java public class MyDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (in.readableBytes() < 4) { return; } int length = in.readInt(); if (in.readableBytes() < length) { in.resetReaderIndex(); return; } byte[] data = new byte[length]; in.readBytes(data); MyMessage message = new MyMessage(length, data); out.add(message); } } ``` 在这个示例中,我们定义了一个名为MyDecoder的解码器,它继承自ByteToMessageDecoder,并实现了decode方法。在decode方法中,我们首先判断ByteBuf中是否有足够的字节可读,如果不够则直接返回。然后从ByteBuf中读取消息的长度和数据,并将它们封装成MyMessage对象,加入到解码结果列表中。 在使用自定义编码器和解码器时,只需要将它们注册到ChannelPipeline中即可。以下是注册的示例代码: ```java ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new MyDecoder()); pipeline.addLast(new MyEncoder()); ``` 这样,在ChannelPipeline中的所有ChannelHandler都可以使用MyMessage对象,而无需关心它们与字节流的转换过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr-X~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值