本博文主要分析服务器的启动的源码,主要分析ChannelFuture f = b.bind(8888).sync()原理。
服务器启动代码public final class SimpleServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .handler(new SimpleServerHandler()) .childHandler(new SimpleServerInitializer()) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(8888).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }ChannelFuture f = b.bind(8888).sync() AbstractBootstrap.java
public ChannelFuture bind(int inetPort) { return bind(new InetSocketAddress(inetPort)); }
public ChannelFuture bind(SocketAddress localAddress) { validate(); //相关参数的检查 if (localAddress == null) { throw new NullPointerException("localAddress"); } //绑定方法 return doBind(localAddress); }validate()方法
//函数功能:检查相关参数是否设置了 @SuppressWarnings("unchecked") public B validate() { //这里的group指的是:b.group(bossGroup, workerGroup)代码中的bossGroup if (group == null) { throw new IllegalStateException("group not set"); } if (channelFactory == null) { throw new IllegalStateException("channel or channelFactory not set"); } return (B) this; }
该方法主要检查了两个参数,一个是group,一个是channelFactory,在这里可以想一想这两个参数是在哪里以及何时被赋值的?答案是在如下代码块中被赋值的,其中是将bossGroup赋值给了group,将BootstrapChannelFactory赋值给了channelFactory。
ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class)doBind(localAddress)方法
private ChannelFuture doBind(final SocketAddress localAddress) { final ChannelFuture regFuture = initAndRegister();//1 final Channel channel = regFuture.channel();//2 if (regFuture.cause() != null) { return regFuture; } final ChannelPromise promise; if (regFuture.isDone()) { promise = channel.newPromise(); doBind0(regFuture, channel, localAddress, promise); } else { // Registration future is almost always fulfilled already, but just in case it's not. promise = new PendingRegistrationPromise(channel); regFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { doBind0(regFuture, channel, localAddress, promise); } }); } return promise; }
doBind这个函数是我们要分析的重点,这个函数的主要工作有如下几点:
- 1、通过initAndRegister()方法得到一个ChannelFuture的实例regFuture。
- 2、通过regFuture.cause()方法判断是否在执行initAndRegister方法时产生来异常。如果产生来异常,则直接返回,如果没有产生异常则进行第3步。
- 3、通过regFuture.isDone()来判断initAndRegister方法是否执行完毕,如果执行完毕来返回true,然后调用doBind0进行socket绑定。如果没有执行完毕则返回false进行第4步。
- 4、regFuture会添加一个ChannelFutureListener监听,当initAndRegister执行完成时,调用operationComplete方法并执行doBind0进行socket绑定。
第3、4点想干的事就是一个:调用doBind0方法进行socket绑定。
initAndRegister()final ChannelFuture initAndRegister() { //结论:这里的channel为一个NioServerSocketChannel对象,具体分析见后面 final Channel channel = channelFactory().newChannel();//1 try { init(channel);//2 } catch (Throwable t) { channel.unsafe().closeForcibly(); // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t); } ChannelFuture regFuture = group().register(channel);//3 if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } } return regFuture; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)