美文网首页
服务端绑定端口

服务端绑定端口

作者: Young_5942 | 来源:发表于2019-12-12 15:21 被阅读0次

服务端启动过程中

ServerBootstrap serverBootstrap = new ServerBootstrap();
...
ChannelFuture sync = serverBootstrap.bind(8089).sync();

会调用父类AbstractBootstrap.bind()

public ChannelFuture bind(int inetPort) {
        return bind(new InetSocketAddress(inetPort));
}

public ChannelFuture bind(SocketAddress localAddress) {
        validate();
        return doBind(ObjectUtil.checkNotNull(localAddress, "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;
        }
    }

initAndRegister实现

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            //通过反射创建NioServerSocketChannel实例
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                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);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        // If we are here and the promise is not failed, it's one of the following cases:
        // 1) If we attempted registration from the event loop, the registration has been completed at this point.
        //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
        // 2) If we attempted registration from the other thread, the registration request has been successfully
        //    added to the event loop's task queue for later execution.
        //    i.e. It's safe to attempt bind() or connect() now:
        //         because bind() or connect() will be executed *after* the scheduled registration task is executed
        //         because register(), bind(), and connect() are all bound to the same thread.

        return regFuture;
    }

init(channel) 在ServerBootstrap中实现

 @Override
    void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }
         
        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
        }

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

doBind0 实现
其中 channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
会调用 AbstractChannel doBind() 实现

 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());
                }
            }
        });
    }

实际的端口绑定实现 通过AbstractChannel doBind()实现,具体实现在NioServerSocketChannel

 /**
     * Bind the {@link Channel} to the {@link SocketAddress}
     */
    protected abstract void doBind(SocketAddress localAddress) throws Exception;

NioServerSocketChannel中的dobind() 调用jdk底层的ServerSocketChannel 绑定端口

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

此处的javaChannel()返回的是 jdk底层的服务端channel:ServerSocketChannel

相关文章

  • 服务端绑定端口

    服务端启动过程中 会调用父类AbstractBootstrap.bind() initAndRegister实现 ...

  • 2018-04-21

    socket中服务端中的bind和listen都是绑定和听自己本地的端口

  • 收集常用端口信息

    文件共享端口 远程连接端口 Web应用服务端口 数据库服务端口 邮件服务端口 网络常见协议端口 特殊服务端口

  • 传统的网络编程思路和方法

    网络编程需要客户端和服务端: 服务端的步奏如下: 1. 创建 ServerSocket 2. 绑定端口Server...

  • 第 4 章 传输

    使用 JDK 的 NIO 实现异步的服务端,大体包括 创建 Channel=>绑定端口=>注册监听=>处理连接建立...

  • 网络编程-socket

    TCP TCP服务端 创建套接字socket 绑定端口bind 侦听客户请求listen 接受客户连接accept...

  • Netty源码分析系列--10. Channel注册到Event

    Channel的注册到EventLoop 前文中介绍了服务端ServerBootStrap绑定端口号时,很重要的一...

  • 网络编程之UDP套接字编程

    UDP套接字服务端 创建UDP数据报套接字 绑定服务端地址(本机的IP和端口号) 消息的收发 关闭套接字 UDP套...

  • linux c++ socket通信2

    转载 服务端:服务器端初始化socket,然后与端口绑定,对端口进行监听,调用accept阻塞,等待客户端连接。s...

  • Redis 安全优化

    Security 非特权运行 文件权限 接口绑定 更改默认服务端口 认证配置 禁用特定命令 日志记录 防范字符串转...

网友评论

      本文标题:服务端绑定端口

      本文链接:https://www.haomeiwen.com/subject/afrtnctx.html