【Netty源码分析】Netty服务端bind端口过程

来源:互联网 发布:开发企业软件平台 编辑:程序博客网 时间:2024/05/22 04:26

这一篇博客我们介绍一下Netty服务端绑定端口的过程,我们通过跟踪代码一直到NIO原生绑定端口的操作。

绑定端口操作

ChannelFuture future = serverBootstrap.bind(8080).sync();

AbstractBootstrap中bind操作

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);    }
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);            return promise;        } else {            // Registration future is almost always fulfilled already, but just in case it's not.            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);            regFuture.addListener(new ChannelFutureListener() {                @Override                public void operationComplete(ChannelFuture future) throws Exception {                    Throwable cause = future.cause();                    if (cause != null) {                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an                        // IllegalStateException once we try to access the EventLoop of the Channel.                        promise.setFailure(cause);                    } else {                        // Registration was successful, so set the correct executor to use.                        // See https://github.com/netty/netty/issues/2586                        promise.registered();                        doBind0(regFuture, channel, localAddress, promise);                    }                }            });            return promise;        }    }
最终的操作是在doBind0函数中,在线程池中添加一个任务,任务的操作是通过Channel来绑定端口等,在线程池中添加一个任务时会开启Server端的服务监听线程。

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());                }            }        });    }
bind操作是在AbstractChannel
 @Override    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {        return pipeline.bind(localAddress, promise);    }
 @Override    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {        return tail.bind(localAddress, promise);    }
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {        if (invokeHandler()) {            try {                ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);            } catch (Throwable t) {                notifyOutboundHandlerException(t, promise);            }        } else {            bind(localAddress, promise);        }    }
HeadContext中调用bind函数,具体实现在Unsafe中。

@Overridepublic void bind(    ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)                throws Exception {    unsafe.bind(localAddress, promise);}
AbstractUnsafe中调用bind函数
@Overridepublic final void bind(final SocketAddress localAddress, final ChannelPromise promise) {........doBind(localAddress);.......}

最终在NioServerSocketChannle中调用doBind函数,javaChannel其实获得的对象就是ServerSocketChannel。

@Overrideprotected void doBind(SocketAddress localAddress) throws Exception {    if (PlatformDependent.javaVersion() >= 7) {        javaChannel().bind(localAddress, config.getBacklog());    } else {        javaChannel().socket().bind(localAddress, config.getBacklog());    }}
这样就完成了服务端的端口绑定过程,同时在绑定端口的过程会调用线程池中的任务,运行一个监听线程。







1 0