Netty源码解析之服务器启动

服务器启动源码

查看流程

// 通过nio方式来接收连接和处理连接
 private EventLoopGroup bg = new NioEventLoopGroup();
 private EventLoopGroup wg = new NioEventLoopGroup();
 //启动引导器
 private ServerBootstrap b = new ServerBootstrap();
 //1 设置reactor 线程
 b.group(bg, wg);
 //2 设置nio类型的channel
 b.channel(NioServerSocketChannel.class);
 //3 设置监听端口
 String ip = IOUtil.getHostAddress();
 b.localAddress(new InetSocketAddress(ip, port));
 //4 设置通道选项,传入TCP参数放入一个LinkedHashMap
 b.option(ChannelOption.SO_KEEPALIVE, true);
 b.option(ChannelOption.ALLOCATOR,
         PooledByteBufAllocator.DEFAULT);
//5 装配流水线,传入一个handler,在每个客户端连接的时候调用
 b.childHandler(new ChannelInitializer<SocketChannel>() {
      //有连接到达时会创建一个channel
      protected void initChannel(SocketChannel ch) throws Exception {
          // 管理pipeline中的Handler
          ch.pipeline().addLast("deCoder",new ProtobufDecoder());
          ch.pipeline().addLast("enCoder",new ProtobufEncoder());
          ch.pipeline().addLast("heartBeat",new HeartBeatServerHandler());
      }
  });
// 6 开始绑定server
// 通过调用sync同步方法阻塞直到绑定成功

ChannelFuture channelFuture = null;
boolean isStart = false;
while (!isStart) {
    try {
        channelFuture = b.bind().sync();
        isStart = true;
    } catch (Exception e) {
        log.error("发生启动异常", e);
        port++;
        log.info("尝试一个新的端口:" + port);
        b.localAddress(new InetSocketAddress(port));
    }
}
ImWorker.getInst().setLocalNode(ip, port);
FutureTaskScheduler.add(() -> {
    /**
     * 启动节点
     */
    ImWorker.getInst().init();
    /**
     * 启动节点的管理
     */
    PeerManager.getInst().init();
});
try {
   // 7 监听通道关闭事件
     // 应用程序会一直等待,直到channel关闭
     ChannelFuture closeFuture =
             channelFuture.channel().closeFuture();
     closeFuture.sync();
 } catch (
         Exception e) {
     log.error("发生其他异常", e);
 } finally {
     // 8 优雅关闭EventLoopGroup,
     // 释放掉所有资源包括创建的线程
     wg.shutdownGracefully();
     bg.shutdownGracefully();
 }

NioEventLoopGroup

默认线程数为cpu核数*2

private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));

    protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
    }
MultithreadEventExecutorGroup
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
        this.terminatedChildren = new AtomicInteger();
        this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        } else {
            if (executor == null) {
                executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
            }

            this.children = new EventExecutor[nThreads];

            int j;
            for(int i = 0; i < nThreads; ++i) {
                boolean success = false;
                boolean var18 = false;

                try {
                    var18 = true;
                    this.children[i] = this.newChild((Executor)executor, args);
                    success = true;
                    var18 = false;
                } catch (Exception var19) {
                    throw new IllegalStateException("failed to create a child event loop", var19);
                } finally {
                    if (var18) {
                        if (!success) {
                            int j;
                            for(j = 0; j < i; ++j) {
                                this.children[j].shutdownGracefully();
                            }

                            for(j = 0; j < i; ++j) {
                                EventExecutor e = this.children[j];

                                try {
                                    while(!e.isTerminated()) {
                                        e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                                    }
                                } catch (InterruptedException var20) {
                                    Thread.currentThread().interrupt();
                                    break;
                                }
                            }
                        }

                    }
                }

                if (!success) {
                    for(j = 0; j < i; ++j) {
                        this.children[j].shutdownGracefully();
                    }

                    for(j = 0; j < i; ++j) {
                        EventExecutor e = this.children[j];

                        try {
                            while(!e.isTerminated()) {
                                e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException var22) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }

            this.chooser = chooserFactory.newChooser(this.children);
            FutureListener<Object> terminationListener = new FutureListener<Object>() {
                public void operationComplete(Future<Object> future) throws Exception {
                    if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
                        MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
                    }

                }
            };
            EventExecutor[] var24 = this.children;
            j = var24.length;

            for(int var26 = 0; var26 < j; ++var26) {
                EventExecutor e = var24[var26];
                e.terminationFuture().addListener(terminationListener);
            }

            Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
            Collections.addAll(childrenSet, this.children);
            this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
        }
    }

1、如果exector是空,创建一个默认的ThreadPreTaskExecutor,使用netty的默认线程工厂
2、根据传入的线程数创建一个(单例)线程池数组
3、循环填充数组中的元素,如果异常,关闭所有单例线程池
4、根据线程池选择工厂创建一个线程选择器
5、为每一个单例线程池添加一个关闭监听器
6、将所有的线程池添加到一个LinkedHashSet

ServerBootstrap

 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
 private final Map<ChannelOption<?>, Object> childOptions = new ConcurrentHashMap();
 private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap();
 private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
 private volatile EventLoopGroup childGroup;
 private volatile ChannelHandler childHandler;

 public ServerBootstrap() {
 }

ServerBootstrap是一个空的构造器,但有默认成员变量

绑定端口

private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = this.initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    } else if (regFuture.isDone()) {
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.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();
                    AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
                }

            }
        });
        return promise;
    }
}

doBind核心是两个方法,initAndRegister和doBind0

final ChannelFuture initAndRegister() {
	  Channel channel = null;
	
	  try {
	      channel = this.channelFactory.newChannel();
	      this.init(channel);
	  } catch (Throwable var3) {
	      if (channel != null) {
	          channel.unsafe().closeForcibly();
	          return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
	      }
	
	      return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
	  }
	
	  ChannelFuture regFuture = this.config().group().register(channel);
	  if (regFuture.cause() != null) {
	      if (channel.isRegistered()) {
	          channel.close();
	      } else {
	          channel.unsafe().closeForcibly();
	      }
	  }
	
	  return regFuture;
	}
channel = this.channelFactory.newChannel();
  1. 通过Nio的SelectorProvider的openServerSocketChannel方法得到JDK的channel,以供netty包装
  2. 创建唯一的channelId,创建一个NioMessageUnsafe,用于操作消息,创建一个DefaultChannelPopeLine管道(双向链表)用于过滤所有进出消息
  3. 创建一个NioServerSocketChannelConfig对象,用于对外展示配置
this.init(channel); 是一个抽象方法,由AbstractBootstrap实现
void init(Channel channel) {
        setChannelOptions(channel, (Entry[])this.options0().entrySet().toArray(newOptionArray(0)), logger);
        setAttributes(channel, (Entry[])this.attrs0().entrySet().toArray(newAttrArray(0)));
        ChannelPipeline p = channel.pipeline();
        final EventLoopGroup currentChildGroup = this.childGroup;
        final ChannelHandler currentChildHandler = this.childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = (Entry[])this.childOptions.entrySet().toArray(newOptionArray(0));
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = (Entry[])this.childAttrs.entrySet().toArray(newAttrArray(0));
        p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = ServerBootstrap.this.config.handler();
                if (handler != null) {
                    pipeline.addLast(new ChannelHandler[]{handler});
                }

                ch.eventLoop().execute(new Runnable() {
                    public void run() {
                        pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
                    }
                });
            }
        }});
    }
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        AbstractChannelHandlerContext newCtx;
        synchronized(this) {
            checkMultiplicity(handler);
            newCtx = this.newContext(group, this.filterName(name, handler), handler);
            this.addLast0(newCtx);
            if (!this.registered) {
                newCtx.setAddPending();
                this.callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                this.callHandlerAddedInEventLoop(newCtx, executor);
                return this;
            }
        }

        this.callHandlerAdded0(newCtx);
        return this;
    }

1、检测handler是否标准
2、创建一个AbstractChannelHandlerContext对象,每当channelHandler添加到pipeline都会创建context,它的主要功能是管理它所关联的handler和统一pipeline中其他handler的交互
3、将context添加到链表
4、同步/异步/晚点异步 进行回调

protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            this.javaChannel().bind(localAddress, this.config.getBacklog());
        } else {
            this.javaChannel().socket().bind(localAddress, this.config.getBacklog());
        }

    }

调用JavaChannel的绑定方法

public final void bind(SocketAddress localAddress, ChannelPromise promise) {
            this.assertEventLoop();
            if (promise.setUncancellable() && this.ensureOpen(promise)) {
                if (Boolean.TRUE.equals(AbstractChannel.this.config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
                    AbstractChannel.logger.warn("A non-root user can't receive a broadcast packet if the socket is not bound to a wildcard address; binding to a non-wildcard address (" + localAddress + ") anyway as requested.");
                }

                boolean wasActive = AbstractChannel.this.isActive();

                try {
                    AbstractChannel.this.doBind(localAddress);
                } catch (Throwable var5) {
                    this.safeSetFailure(promise, var5);
                    this.closeIfClosed();
                    return;
                }

                if (!wasActive && AbstractChannel.this.isActive()) {
                    this.invokeLater(new Runnable() {
                        public void run() {
                            AbstractChannel.this.pipeline.fireChannelActive();
                        }
                    });
                }

                this.safeSetSuccess(promise);
            }
        }

调用到safeSetSuccess,就可以告诉promise任务完成进行监听

protected void run() {
        while(true) {
            while(true) {
                while(true) {
                    try {
                        try {
                            switch(this.selectStrategy.calculateStrategy(this.selectNowSupplier, this.hasTasks())) {
                            case -3:
                            case -1:
                                this.select(this.wakenUp.getAndSet(false));
                                if (this.wakenUp.get()) {
                                    this.selector.wakeup();
                                }
                                break;
                            case -2:
                                continue;
                            }
                        } catch (IOException var23) {
                            this.rebuildSelector0();
                            handleLoopException(var23);
                            continue;
                        }

                        this.cancelledKeys = 0;
                        this.needsToSelectAgain = false;
                        int ioRatio = this.ioRatio;
                        if (ioRatio == 100) {
                            try {
                                this.processSelectedKeys();
                            } finally {
                                this.runAllTasks();
                            }
                        } else {
                            long ioStartTime = System.nanoTime();
                            boolean var14 = false;

                            try {
                                var14 = true;
                                this.processSelectedKeys();
                                var14 = false;
                            } finally {
                                if (var14) {
                                    long ioTime = System.nanoTime() - ioStartTime;
                                    this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                                }
                            }

                            long ioTime = System.nanoTime() - ioStartTime;
                            this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                        }
                    } catch (Throwable var24) {
                        handleLoopException(var24);
                    }
                    break;
                }

                try {
                    if (this.isShuttingDown()) {
                        this.closeAll();
                        if (this.confirmShutdown()) {
                            return;
                        }
                    }
                } catch (Throwable var20) {
                    handleLoopException(var20);
                }
            }
        }
    }

到run方法无限循环,服务器端启动

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值