Netty源码分析(二)—客户端初始化
来源:互联网 发布:大数据岗位 知乎 编辑:程序博客网 时间:2024/05/18 02:19
Netty源码分析(二)—客户端初始化
传统Java NIO在客户端启动时会涉及到SocketChannel,Selector,selectorKey等类;Netty对Java NIO基础类进行了封装,减少用户开发工作量,降低开发难度;
个人主页:tuzhenyu’s page
原文地址:Netty源码分析(二)—客户端初始化
(0)客户端初始化
客户端初始化的步骤
创建Bootstrap启动辅助类,通过Builder模式进行参数配置;
创建并绑定Reactor线程池EventLoopGroup;
设置并绑定服务端Channel通道类型;
绑定服务端通道数据处理器责任链Handler;
连接特定IP和端口;
客户端初始化实例
private void connect(String host,int port){ EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new TimeClientHandler()); } }); ChannelFuture f = b.connect(host,port).sync(); f.channel().closeFuture().sync(); }catch (Exception e){ e.printStackTrace(); }finally { group.shutdownGracefully(); }}
(1) Bootstrap初始化
- ServerBootstrap继承AbstracBootstrap类,需要对EventLoopGroup,Channel和ChannelHandler等参数进行配置;
(2) EventLoopGroup线程池初始化
- EventLoopGroup初始化是创建创建一个NioEventLoopGroup类型的Reactor线程池group分别用来通道IO事件;
EventLoopGroup group = new NioEventLoopGroup();BootStrap b = new Bootstrap();b.group(group);
- 将group赋值给AbstractBootstrap的group属性,用作后续调用;
public B group(EventLoopGroup group) { if(group == null) { throw new NullPointerException("group"); } else if(this.group != null) { throw new IllegalStateException("group set already"); } else { this.group = group; return this; }}
(3) Channel通道初始化
Channel初始化主要是指对通道类型进行设置,常见的通道类型主要有NioServerSocktChannel异步非阻塞服务端TCP通道,NioSocketChannel异步非阻塞客户端通道,OioServerSocketChannel同步阻塞服务端通道,OioSocketChannel同步阻塞客户端通道,NioDatagramChannel异步非阻塞UDP通道,OioDatagramChannel同步阻塞UDP通道等;
在serverBootstrap初始化过程中通过调用channel()方法进行通道类型设置
public B channel(Class<? extends C> channelClass) { if(channelClass == null) { throw new NullPointerException("channelClass"); } else { return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass))); }}
- 根据传入的Channe类型初始化一个ChannelFactory类型的工厂类,工厂类中通过newChannel()方法创建Channel实例
private final Class<? extends T> clazz;public ReflectiveChannelFactory(Class<? extends T> clazz) { if(clazz == null) { throw new NullPointerException("clazz"); } else { this.clazz = clazz; }}public T newChannel() { try { return (Channel)this.clazz.newInstance(); } catch (Throwable var2) { throw new ChannelException("Unable to create Channel from class " + this.clazz, var2); }}
- 通过channelFactory()方法将创建工厂类实例指向AbstractoryBootstrap的channelFactory属性
public B channelFactory(ChannelFactory<? extends C> channelFactory) { if(channelFactory == null) { throw new NullPointerException("channelFactory"); } else if(this.channelFactory != null) { throw new IllegalStateException("channelFactory set already"); } else { this.channelFactory = channelFactory; return this; }}
(4)handler处理器的添加过程
- 我们可以自定义Handler处理器并将其加入到pipeline管道中,进而像插件一样自由组合各种handler完成具体的业务逻辑;添加handler的过程是获取与channel通道绑定的管道pipeline然后将自定义的handler添加进pipeline内部维护的一个双向链表;
bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new TimeClientHandler()); }});
- Bootstrap.handler方法接收一个 ChannelHandler, 而我们传递的是一个 派生于ChannelInitializer的匿名类, 它正好也实现了 ChannelHandler接口;在channelInitializer抽象类中存在抽象方法initChannel()需要实现,同时在ChannelInitializer类中channelRegistered方法调用initChannle()方法实现handler处理器添加到pipeline管道中;
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class); protected abstract void initChannel(C ch) throws Exception; @Override @SuppressWarnings("unchecked") public final void channelRegistered(ChannelHandlerContext ctx) throws Exception { initChannel((C) ctx.channel()); ctx.pipeline().remove(this); ctx.fireChannelRegistered(); } ...}
- 在 channelRegistered 方法中, 会调用initChannel 方法, 将自定义的 handler 添加到 ChannelPipeline 中, 然后调用 ctx.pipeline().remove(this) 将自己从 ChannelPipeline 中删除.
(5)客户端的连接过程
- 完成启动辅助类Bootstrap的参数配置后调用connect()方法连接服务端
public ChannelFuture connect(SocketAddress remoteAddress) { if(remoteAddress == null) { throw new NullPointerException("remoteAddress"); } else { this.validate(); return this.doResolveAndConnect(remoteAddress, this.config.localAddress()); }}
- connect()方法调用validate()方法看各个Part是否准备就绪,然后调用doResolveAndConnect()方法:
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) { ChannelFuture regFuture = this.initAndRegister(); final Channel channel = regFuture.channel(); if(regFuture.isDone()) { return !regFuture.isSuccess()?regFuture:this.doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise()); } else { final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel); regFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { Throwable cause = future.cause(); if(cause != null) { promise.setFailure(cause); } else { promise.registered(); Bootstrap.this.doResolveAndConnect0(channel, remoteAddress, localAddress, promise); } } }); return promise; }}
- 通过调用initAndRegister()方法用ChannelFactory创建了一个Channel的实例,然后调用init()方法初始化Channel,最后将Channel注册到EventLoopGroup上:
总结
- 客户端初始化和服务端初始化基本相同,区别在于Channel的类型设置和Handler处理链的添加等
阅读全文
0 0
- Netty源码分析(二)—客户端初始化
- Netty 源码分析(二)
- Netty源码分析(一)—服务端初始化
- Netty(二):服务端客户端实例分析
- netty 源码分析二
- Netty源码分析:客户端连接
- netty源码分析之客户端
- netty 客户端初始化 and 注册过程分析
- Netty 源码分析之 一 客户端创建(Bootstrap )
- netty(十七)源码分析之客户端创建
- Netty源码解读------------客户端接入绑定(二)
- 【Netty源码分析】客户端connect服务端过程
- Netty系列-客户端启动源码分析
- Ceph Monitor源码机制分析(二)—— 初始化
- netty(十一)源码分析之ByteBuf 二
- Netty源码分析(五)—ByteBuf源码分析
- netty源码分析(二)-处理请求
- netty源码分析 之二 transport(bootstrap)
- 左偏树
- 修改客户地址别名报错APP-AR-294464
- 微信运营注意什么问题?公众平台运营问题解答。
- hdu 1824 Let's go home (2-sate)
- 购物车的修改查找排序批量删除
- Netty源码分析(二)—客户端初始化
- 数据结构实验之图论六:村村通公路
- Android用NoHttp+MVP构建项目框架
- 2017_11_22 学习Json数据与Java对象互转的两种方式(一)
- Spring—InitializingBean
- Ubuntu系统使用Doxygen生成文档
- postgres 并发控制
- docker 学习有感
- java导出简单的word模板