netty源碼分析之一:server的啟動

來源:互聯網
上載者:User

標籤:loop   inbound   ios   equal   sse   pack   int   roc   not   

nio server啟動的第一步,都是要建立一個serverSocketChannel,我截取一段啟動代碼,一步步分析:

public void afterPropertiesSet() throws Exception {
// 建立rpc工廠
ThreadFactory threadRpcFactory = new NamedThreadFactory("NettyRPC ThreadFactory");
//執行worker線程池數量
int parallel = Runtime.getRuntime().availableProcessors() * 2;
// boss
EventLoopGroup boss = new NioEventLoopGroup(1);
// worker
EventLoopGroup worker = new NioEventLoopGroup(parallel,threadRpcFactory, SelectorProvider.provider());
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
.childHandler(new MessageRecvChannelInitializer(handlerMap))
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture future = bootstrap.bind(serverAddress, Integer.valueOf(port)).sync();
System.out.printf("[author chenjianye] Netty RPC Server start success ip:%s port:%s\n", serverAddress, port);

// 註冊zookeeper服務
serviceRegistry.register(serverAddress + ":" + port);
// wait
future.channel().closeFuture().sync();
} finally {
worker.shutdownGracefully();
boss.shutdownGracefully();
}
}
入口就在
ChannelFuture future = bootstrap.bind(serverAddress, Integer.valueOf(port)).sync();

順序往下執行,直到AbstractBootstrap類的doBind方法:
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 promise1 = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise1);
return promise1;
} else {
final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel, null);
regFuture.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if(cause != null) {
promise.setFailure(cause);
} else {
promise.executor = channel.eventLoop();
}

AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
}
});
return promise;
}
}
=============================================
這個方法需要重點分析,我做個標記,doBind方法分析如下:

1.final ChannelFuture regFuture = this.initAndRegister();
final ChannelFuture initAndRegister() {
// 通過channel工廠反射建立ServerSocketChannel,並建立了作用於serverSocketChannel的channelPipeline管道
// 這個管道維護了ctx為元素的雙向鏈表,到目前為止,pipeline的順序為:head(outBound) ----> tail(inbound)
Channel channel = this.channelFactory().newChannel();

try {
     // 這個init方法第一個主要是設定channel的屬性,我不細說了
// 第二個作用是增加了inbound處理器,channelInitializer,裡面有一個initChannel()方法會在特定時刻被觸發,什麼時候被觸發,後面我會說到。
this.init(channel);
} catch (Throwable var3) {
channel.unsafe().closeForcibly();
return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
}

   // 到了這裡,就開始執行register邏輯,這個是關鍵,我把register的代碼貼出來,跟著後面的代碼繼續看,跳轉到2。
ChannelFuture regFuture = this.group().register(channel);
if(regFuture.cause() != null) {
if(channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}

return regFuture;
}
2.AbstractChannel裡的register方法:
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if(eventLoop == null) {
throw new NullPointerException("eventLoop");
} else if(AbstractChannel.this.isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
} else if(!AbstractChannel.this.isCompatible(eventLoop)) {
promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
} else {
AbstractChannel.this.eventLoop = eventLoop;
// 到這裡還是主線程啟動,所以會執行else,啟動了boss線程,register0方法跳轉到3
if(eventLoop.inEventLoop()) {
this.register0(promise);
} else {
try {
eventLoop.execute(new OneTimeTask() {
public void run() {
AbstractUnsafe.this.register0(promise);
}
});
} catch (Throwable var4) {
AbstractChannel.logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, var4);
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var4);
}
}

}
}
3.register0方法
private void register0(ChannelPromise promise) {
try {
if(!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}

boolean t = this.neverRegistered;
// 這個方法主要是 this.selectionKey = this.javaChannel().register(this.eventLoop().selector, 0, this);
        AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;

// 回調之前doBind方法的listener,boss線程添加了新的任務:bind任務
this.safeSetSuccess(promise);

// 這個方法東西內容很多
// 第一步:this.head.fireChannelRegistered()沒有什麼實質內容,最終執行到inbound的next.invokeChannelRegistered()方法
// 第二步:根據上文,目前的pipeline順序為head---->initializer---->tail
// 第三步:執行initializer
// 第四步:添加一個新的inbound處理器,ServerBootstrapAcceptor,此時的順序為:head---->initizlizer---->ServerBootstrapAcceptor---->tail
// 第五步:移除initizlizer,此時pipeline順序為:head---->ServerBootstrapAcceptor---->tail
// 第六步:麼有什麼實質內容,這個方法就算執行結束了
AbstractChannel.this.pipeline.fireChannelRegistered();

// 這裡channel還沒有綁定,所以isActive()方法返回false,不會繼續執行,目前boss線程還剩下bind任務
if(t && AbstractChannel.this.isActive()) {
AbstractChannel.this.pipeline.fireChannelActive();
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}

}
4.bind任務
bind任務是一個outbound,所以會按照tail---->head的順序執行,目前只有head是outbound。
headHandler最終會執行AbstractUnsafe的bind方法:
AbstractChannel.this.doBind(localAddress);
public final void bind(SocketAddress localAddress, ChannelPromise promise) {
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.isRoot()) {
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 {
       //由於我們是nioServerSocketChannel,所以:this.javaChannel().socket().bind(localAddress, this.config.getBacklog());

AbstractChannel.this.doBind(localAddress);

} catch (Throwable var5) {
 this.safeSetFailure(promise, var5);
this.closeIfClosed();
return;
}

     // 此時已經綁定了,所以isActive()返回true,執行
if(!wasActive && AbstractChannel.this.isActive()) {
// 重新往boss線程加入了任務
this.invokeLater(new OneTimeTask() {
public void run() {
AbstractChannel.this.pipeline.fireChannelActive();
}
});
}

this.safeSetSuccess(promise);
}
}

public ChannelPipeline fireChannelActive() {
// 來回調用,貌似這裡沒有什麼實質內容
this.head.fireChannelActive();
if(this.channel.config().isAutoRead()) {
// 這個是outBound,最終會觸發head
     // head會執行 this.unsafe.beginRead(),最終會執行abstractNioChannel裡的doBeginRead()方法,最終會執行到5
        this.channel.read();
}

return this;
}
5.
protected void doBeginRead() throws Exception {
if(!this.inputShutdown) {
SelectionKey selectionKey = this.selectionKey;
if(selectionKey.isValid()) {
this.readPending = true;
int interestOps = selectionKey.interestOps();
if((interestOps & this.readInterestOp) == 0) {
selectionKey.interestOps(interestOps | this.readInterestOp);
}

}
}
}
終於看到我們熟悉的東西了,最終把selectionKey的interestOps設定為SelectionKey.OP_ACCEPT。












netty源碼分析之一:server的啟動

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.