ChannelPipeline
源码ChannelPipeline的开头描述部分对于netty很有帮助,他解释了 channelHandler,addLast方法,事件传播,以及io线程和业务线程分离等等,推荐各位认真看看。
不管我们上传发送什么数据格式给底层(也就netty层)都要转化为ByteBuf进行传输,也就是最进行io的一定是二进制,其他String或者POJO都要转化为ByteBuf后才可以用。这也是Decoder和Encoder的作用。
而负责分包的LineBasedFrameDecoder,一定是最接近IO,为什么呢?如果先进行对象的转换,那么用多少字节进行对象的构造呢?是不确定的。所以只有先分包,然后用分好的包进行对象的构造。另外,由于分包是接近IO的,所以不管是字符串String分包,还是别的(换行)分包,都会转换为字节码的形式进行匹配。应用如下:
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));// 根据 分隔符(换行符)分割,分割后还是 ByteBuf
ch.pipeline().addLast(new StringDecoder());// 用于inbound 的解析,也就是read(), 从ByteBuf 转换到了String.
ch.pipeline().addLast(new StringEncoder());// 用户outbould ,也就是write() , 从String 转换到了ByteBuf.
ch.pipeline().addLast(
new EchoClientHander());
经过上面的设置后,server的read方法就可以直接读了。
class EchoClientHander extends ChannelInboundHandlerAdapter {
Logger logger=Logger.getLogger(EchoClientHander.class.getName());
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info(msg.toString());
}
}
怎样快速的找到函数调用关系。根据
ChannelPipeline.fireChannelRead() 这是一个触发方法,然后在idea中 ctrl+alt+h ,就可以显示类函数调用关系图。
那么然后就是一点点进行每个步骤的分析。整体流程已经清楚了。
其他
在基类AbstractBootstrap有handler方法,目的是添加一个handler,监听Bootstrap的动作,客户端的Bootstrap中,继承了这一点。
在服务端的ServerBootstrap中增加了一个方法childHandler,它的目的是添加handler,用来监听已经连接的客户端的Channel的动作和状态。
handler在初始化时就会执行,而childHandler会在客户端成功connect后才执行,这是两者的区别。