https://blog.51cto.com/483181/2121265
站在用戶的角度思考問題,與客戶深入溝通,找到玉門網(wǎng)站設(shè)計(jì)與玉門網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋玉門地區(qū)。
我們繼續(xù)分析doBind0(regFuture, channel, localAddress, promise)
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise); //3. 我們這篇要分析的內(nèi)容
return promise;
} else {
...
return promise;
}
}
如上面代碼,doBind0有4個(gè)參數(shù)regFuture, channel, localAddress, promise,它們的類型如下:
regFuture: DefaultChannelPromise
channel:NioServerSocketChannel
localAddress:SocketAddress
promise:DefaultChannelPromise
那繼續(xù)往下面看代碼,
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
doBind0()代碼很簡(jiǎn)單,調(diào)用channel.eventloop()執(zhí)行了一個(gè)Runnable。channel.eventloop()調(diào)用的是AbstractChannle.eventloop()
@Override
public EventLoop eventLoop() {
EventLoop eventLoop = this.eventLoop;
if (eventLoop == null) {
throw new IllegalStateException("channel not registered to an event loop");
}
return eventLoop;
}
而this.eventLoop初始化是在register的時(shí)候,具體可以參考上一篇bind初始化的分析
https://blog.51cto.com/483181/2121265
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
....
AbstractChannel.this.eventLoop = eventLoop;
...
}
它的類型是一個(gè)NioEventLoop,所以它就是往自己的線程池里面丟了一個(gè)Runnable任務(wù)
NioEventLoop的繼承關(guān)系圖如下:
我們可以看一下NioEventLoop.execute(Runnable )方法.
這個(gè)方法的實(shí)現(xiàn)是在SingleThreadEventExecutor.java里面。
private final Queue<Runnable> taskQueue;
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
addTask(task);
if (!inEventLoop) {
startThread();
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
protected void addTask(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
if (!offerTask(task)) {
reject(task);
}
}
final boolean offerTask(Runnable task) {
if (isShutdown()) {
reject();
}
return taskQueue.offer(task);
}
它是把傳入的Runnable對(duì)象放到一個(gè)taskQueue隊(duì)列里面。
那我們繼續(xù)看Runnable里面的實(shí)現(xiàn),channel.bind(xxxx)
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
...
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
Channel的類型是NioServerSocketChannel,而bind方法的實(shí)現(xiàn)類是在AbstractChannel.java里面.
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
調(diào)用的是pipeline.bind(xxx),pipeline我們知道,它鏈接了ChannelHandler的Context,有head和tail。head是outbound,tail是inbound.
DefaultChannelPipeline.java
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
直接調(diào)用的是tail.bind,繼續(xù)往下面看
AbstractChannelHandlerContext.java
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
它調(diào)用findContextOutbound(),然后調(diào)用它的bind方法,從以前的分析可以知道,outbound講的是head。所以,我們來到head.bind方法
DefaultChannelPipeline.java
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
調(diào)用的是unsafe.bind
AbstractChannel.java
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
...
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
...
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
繼續(xù)看doBind()
doBind是在NioServerSocketChannel里面
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
這樣就調(diào)用了Java的接口綁定了我們傳入的端口。
這樣bind邏輯整個(gè)就分析完了,我們來分析一下整個(gè)流程以及類之間的關(guān)系。
分享標(biāo)題:59.Netty源代碼分析-ServerBootstrapbind過程-2
網(wǎng)頁URL:http://jinyejixie.com/article4/ijdsoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、企業(yè)網(wǎng)站制作、軟件開發(fā)、靜態(tài)網(wǎng)站、營(yíng)銷型網(wǎng)站建設(shè)、做網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)