Netty是一个NIO客户端服务端框架与网络编程有什么关系?( 二 )

, Object>[] childOptions, Entry, Object>[] childAttrs) {this.childGroup = childGroup;this.childHandler = childHandler;}public void channelRead(ChannelHandlerContext ctx, Object msg) {final Channel child = (Channel)msg;child.pipeline().addLast(new ChannelHandler[]{this.childHandler});try {this.childGroup.register(child).addListener(new ChannelFutureListener() {});} catch (Throwable var8) {}}}4、EventLoopGroupSingleThreadEventLoopGroup 一个线程处理所有的Channel
ThreadPerChannelLoopGroup 每个线程处理一个channel
MultiThreadEventLoopGroup 通过线程组处理channel
NIOEventLoopGroup
EpollEventLoopGroup 根据Selecter的不同实现 , 不同的处理策略 。 NIOEventLoopGroup , 默认采用sellect方式 , 参考JAVA NIO实现 。 EpollEventLoopGroup只能在linux平台使用 , 更高效 。
5、编程模式宏观上 , ChannelPipline串联起所有的ChannelHandler , 在特定的时间节点 , 调用Handler的函数 , 完成处理流程 。 处理流程如下图所示:
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {public void channelRegistered(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelRegistered();}public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelUnregistered();}public void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelActive();}public void channelInactive(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelInactive();}public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ctx.fireChannelRead(msg);}public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelReadComplete();}public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {ctx.fireUserEventTriggered(evt);}public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelWritabilityChanged();}public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.fireExceptionCaught(cause);}}ChannelPipline:内部包含一个ChannelHandlerContext的链表数据结构 , 每次从header item开始 , 调用context.invoke函数 , 开始处理流程 。
ChannelHandlerContext:在Channelhandler中 , 调用context的fire函数;fire函数在pipline中查找需要执行的下一个context , 调用context.invoke函数;调用channelhandler的函数 。
ChannelHandler:channelChandler分为inbound和outbond , inbound处理接收消息 , outbound处理传出 。 如上所示 , channelInboundHandler中定义了一系列的函数 , 一般情况下 , 编写Netty程序 , 只需要在ChannelHandler中处理业务逻辑 , 编程模型相当简单 。
7、编码与解码代码实例中 , channelHandler中读到的是ByteBuf对象 , 其实就是byte数组 , 在程序内部 , 把byte数组转换成了字符串 。
问题1、半包问题 , 没有读到完整的数据 , 就进行了转换 , 导致错误 。
问题2、编解码与业务柔和在一起 , 设计上不完美 。
Netty提供了编码器 , 解码器以及编解码器 。
public class RpcChannelHandler extends SimpleChannelInboundHandler implements RpcChannel {// 读取数据 , 读的是对象@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse rpcResponse) throws Exception {String requestId = rpcResponse.getRequestId();if (rpcFutureMap.containsKey(requestId)) {RpcFuture rpcFuture = rpcFutureMap.get(requestId);rpcFutureMap.remove(requestId);rpcFuture.finish(rpcResponse);}}@Overridepublic RpcFuture call(RpcRequest request, RpcCallback callback) {this.channel.writeAndFlush(request); // 写数据 , 写的也是对象}} 编码器
public class RpcEncoder extends MessageToByteEncoder {@Overridepublic void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {if (genericClass.isInstance(in)) {byte[] data = http://kandian.youth.cn/index/SerializationUtil.serialize(in);out.writeInt(data.length);out.writeBytes(data);}}}解码器
public class RpcDecoder extends ByteToMessageDecoder {@Overridepublic final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {if (in.readableBytes() < 4) {return;}in.markReaderIndex();int dataLength = in.readInt();if (in.readableBytes() < dataLength) {in.resetReaderIndex();return;}byte[] data = http://kandian.youth.cn/index/new byte[dataLength];in.readBytes(data);Object obj = SerializationUtil.deserialize(data, genericClass);out.add(obj);}}编码解码器类结构
编码器是一个ChannelHandler , 放在pipline中 , 作为处理请求消息的一个环节 。 处理传入参数的是Decoder , 负责把二进制的数据 , 转换成程序可识别的数据结构 , 其实现了InboundChannelHandler接口;一般情况下 , decoder要放在pip的header位置 , 即addFrist 。 处理传出参数的是Encoder , 负责把程序内部的数据结构 , 转换成可在网络传输的二进制数据;一般情况下 , encoder需要放在pipline的最后处理 。