入站出站
ChannelPipeline 提供了ChannelHandler链的容器,以客户端应用程序为例,如果事件的运动方向是从客户端到服务端,称之为出站,即客户端发送给服务端的数据会通过pipeline中的一系列ChannelOutboundHandler,并被这些handler处理,反之则成为入站
编码解码器
1.当netty发送或者接受一个消息的时候,就将会发生一次数据转换,入站消息会被解码,从字节转换为另一种格式(比如java对象);如果是出站消息,它会被编码成字节。
2.netty提供一系列实用的编码解码器,他们都实现了ChannelInboundHandler或者ChannelOutboundHandler接口。在这些类中,channelRead方法已经被重写了,以入站为例,对于每个从入站Channel读取的消息,这个方法会被调用,随后,它将调用由解码器所提供的decode()方法进行解码,并将已经解码的字节转发给ChannelPipeline中的下一个ChannelInboundHandler
解码器ByteToMessageDecoder
1.继承关系图:
2.由于不可能知道远程节点是否会一次性发送一个完整的信息,tcp有可能出现粘包拆包的问题,这个类会对入站数据进行缓冲,知道它准备好被处理。
Netty链式调用机制:
编码解码器在进行编码或者解码结束时,会将转发给Pipeline中的下一个handler,具体执行流程为:
自定义编码器与解码器
编码器:
package com.jym.codeHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/11
*/
public class MyLongToByteEncoder extends MessageToByteEncoder<Long> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Long msg, ByteBuf byteBuf) throws Exception {
System.out.println("encode方法被调用");
System.out.println("msg =" +msg);
byteBuf.writeLong(msg);
}
}
解码器:
package com.jym.codeHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/11
*/
public class MyByteToLongDecoder extends ByteToMessageDecoder {
/**
* decode 会根据接受的数据,被调用多次,知道没有新的元素被添加到List,或者是ByteBuf没有更多个可读字节为止
* 如果list 不为空,就会将list的内容传递给下一个channelInboundHandler,该处理器的方法也会被调用多次
*
* @param channelHandlerContext 上下文对象
* @param byteBuf 入站的byteBuf
* @param list list集合,将解码后的数据传给下一个集合
* @throws Exception
*/
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
// long 8八个字节,大于等于8才处理
if(byteBuf.readableBytes()>=8){
list.add(byteBuf.readLong());
}
}
}
解码器 ReplayingDecoder
1.ReplayingDecoder<> extends ByteToMessageDecoder
2.ReplayingDecoder扩展了ByteToMessageDecoder类,使用这个类,我们不必调用readableBytes方法,参数S指定了用户状态管理类型,其中void代表不需要状态管理
3.应用实例
4.ReplayingDecoder使用方便,但是有局限性
并不是所有的ByteBuf操作都支持,如果调用了不被支持的方法,将会抛出一个异常
ReplayingDecoder 在某些情况下可能稍慢于ByteToMessageDecoder,例如网络缓慢并且消息格式复杂时,消息会拆成多个碎片,效率变低
Netty其他解码器
1 . lineBasedFrameDecoder: 这个类在netty内部也有使用,它使用行位控制符作为分隔符来解析数据
2. DelimiterBasedFrameDecoder:使用自定义的特殊字符作为消息的分隔符
3. HttpObjectDecoder:一个HTTP数据的解码器
4. LengthFieldBasedFrameDecoder:通过指定长度来标识整包消息,这样就可以自动的处理黏包和半包消息