netty-客户端连接过程 源码分析.md

应用程序

客户端.connect()方法

nio框架-netty

private static void doConnect(

            final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {



        // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up

        // the pipeline in its channelRegistered() implementation.

        final Channel channel = connectPromise.channel();

        channel.eventLoop().execute(new Runnable() {

            @Override

            public void run() {

                if (localAddress == null) {

                    channel.connect(remoteAddress, connectPromise); //

                } else {

                    channel.connect(remoteAddress, localAddress, connectPromise); //NioSocketChannel

                }

                connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);

            }

        });

    }


复制代码
private final DefaultChannelPipeline pipeline;


 @Override

    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {

        return pipeline.connect(remoteAddress, localAddress, promise); 

    }

复制代码
final AbstractChannelHandlerContext tail;


@Override

    public final ChannelFuture connect(

            SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {

        return tail.connect(remoteAddress, localAddress, promise); //

ChannelHandlerContext(DefaultChannelPipeline$TailContext#0, [id: 0x28fdf4fa])

    }



复制代码
@Override

    public ChannelFuture connect(

            final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {



        if (remoteAddress == null) {

            throw new NullPointerException("remoteAddress");

        }

        if (isNotValidPromise(promise, false)) {

            // cancelled

            return promise;

        }



        final AbstractChannelHandlerContext next = findContextOutbound();

        EventExecutor executor = next.executor();

        if (executor.inEventLoop()) {

            next.invokeConnect(remoteAddress, localAddress, promise); //

        } else {

            safeExecute(executor, new Runnable() {

                @Override

                public void run() {

                    next.invokeConnect(remoteAddress, localAddress, promise);

                }

            }, promise, null);

        }

        return promise;

    }



private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {

        if (invokeHandler()) {

            try {

                ((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise); //

            } catch (Throwable t) {

                notifyOutboundHandlerException(t, promise);

            }

        } else {

            connect(remoteAddress, localAddress, promise);

        }

    }


复制代码
private final Unsafe unsafe;


 @Override

        public void connect(

                ChannelHandlerContext ctx,

                SocketAddress remoteAddress, SocketAddress localAddress,

                ChannelPromise promise) throws Exception {

            unsafe.connect(remoteAddress, localAddress, promise);

        }


复制代码
@Override

        public final void connect(

                final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {

            if (!promise.setUncancellable() || !ensureOpen(promise)) {

                return;

            }



            try {

                if (connectPromise != null) {

                    // Already a connect in process.

                    throw new ConnectionPendingException();

                }



                boolean wasActive = isActive();

                if (doConnect(remoteAddress, localAddress)) { //

                    fulfillConnectPromise(promise, wasActive);

                } else {

                    connectPromise = promise;

                    requestedRemoteAddress = remoteAddress;



                    // Schedule connect timeout.

                    int connectTimeoutMillis = config().getConnectTimeoutMillis();

                    if (connectTimeoutMillis > 0) {

                        connectTimeoutFuture = eventLoop().schedule(new Runnable() {

                            @Override

                            public void run() {

                                ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;

                                ConnectTimeoutException cause =

                                        new ConnectTimeoutException("connection timed out: " + remoteAddress);

                                if (connectPromise != null && connectPromise.tryFailure(cause)) {

                                    close(voidPromise());

                                }

                            }

                        }, connectTimeoutMillis, TimeUnit.MILLISECONDS);

                    }



                    promise.addListener(new ChannelFutureListener() {

                        @Override

                        public void operationComplete(ChannelFuture future) throws Exception {

                            if (future.isCancelled()) {

                                if (connectTimeoutFuture != null) {

                                    connectTimeoutFuture.cancel(false);

                                }

                                connectPromise = null;

                                close(voidPromise());

                            }

                        }

                    });

                }

            } catch (Throwable t) {

                promise.tryFailure(annotateConnectException(t, remoteAddress));

                closeIfClosed();

            }

        }


复制代码
@Override

    protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {

        if (localAddress != null) {

            doBind0(localAddress);

        }



        boolean success = false;

        try {

            boolean connected = SocketUtils.connect(javaChannel(), remoteAddress); //

            if (!connected) {

                selectionKey().interestOps(SelectionKey.OP_CONNECT);

            }

            success = true;

            return connected;

        } finally {

            if (!success) {

                doClose();

            }

        }

    }


复制代码
public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)

            throws IOException {

        try {

            return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {

                @Override

                public Boolean run() throws IOException {

                    return socketChannel.connect(remoteAddress); //
SocketChannalImpl

                }

            });

        } catch (PrivilegedActionException e) {

            throw (IOException) e.getCause();

        }

    }


复制代码

jdk nio-channel

//sun.nio.channel.ChannelImpl通道实现-SocketChannalImpl

 public boolean connect(SocketAddress sa) throws IOException {

        int localPort = 0;



        synchronized (readLock) {

            synchronized (writeLock) {

                ensureOpenAndUnconnected();

                InetSocketAddress isa = Net.checkAddress(sa);

                SecurityManager sm = System.getSecurityManager();

                if (sm != null)

                    sm.checkConnect(isa.getAddress().getHostAddress(),

                                    isa.getPort());

                synchronized (blockingLock()) {

                    int n = 0;

                    try {

                        try {

                            begin();

                            synchronized (stateLock) {

                                if (!isOpen()) {

                                    return false;

                                }

                                // notify hook only if unbound

                                if (localAddress == null) {

                                    NetHooks.beforeTcpConnect(fd,

                                                           isa.getAddress(),

                                                           isa.getPort());

                                }

                                readerThread = NativeThread.current();

                            }

                            for (;;) {

                                InetAddress ia = isa.getAddress();

                                if (ia.isAnyLocalAddress())

                                    ia = InetAddress.getLocalHost();

                                n = Net.connect(fd,

                                                ia,

                                                isa.getPort());

                                if (  (n == IOStatus.INTERRUPTED)

                                      && isOpen())

                                    continue;

                                break;

                            }



                        } finally {

                            readerCleanup();

                            end((n > 0) || (n == IOStatus.UNAVAILABLE));

                            assert IOStatus.check(n);

                        }

                    } catch (IOException x) {

                        // If an exception was thrown, close the channel after

                        // invoking end() so as to avoid bogus

                        // AsynchronousCloseExceptions

                        close();

                        throw x;

                    }

                    synchronized (stateLock) {

                        remoteAddress = isa;

                        if (n > 0) {



                            // Connection succeeded; disallow further

                            // invocation

                            state = ST_CONNECTED;

                            if (isOpen())

                                localAddress = Net.localAddress(fd);

                            return true;

                        }

                        // If nonblocking and no exception then connection

                        // pending; disallow another invocation

                        if (!isBlocking())

                            state = ST_PENDING;

                        else

                            assert false;

                    }

                }

                return false;

            }

        }

    }


复制代码

//同上包.Net

private static native int connect0(boolean preferIPv6,

                                       FileDescriptor fd,

                                       InetAddress remote,

                                       int remotePort)

        throws IOException; //最终调用的也是native方法。和java net包的socket一样,最终也是调用jvm native方法。


复制代码

总结

1.包 与net包socket的区别 jdk nio包。和net包的socket完全不一样。2种实现方式。一个基于socket/单向读或写流,一个基于双向通道channel(可以同时读写)。

2.流程
nio包——》jvm native——》操作系统

转载于:https://juejin.im/post/5c4be2fde51d45520f198e80

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023-07-14 15:19:01.215 WARN 7308 --- [sson-netty-2-15] io.netty.util.concurrent.DefaultPromise : An exception was thrown by org.redisson.misc.RedissonPromise$$Lambda$888/0x00000008008f7440.operationComplete() java.lang.NullPointerException: null 2023-07-14 15:19:01.216 ERROR 7308 --- [sson-netty-2-15] o.r.c.SentinelConnectionManager : Can't execute SENTINEL commands on /172.24.107.11:26379 org.redisson.client.RedisException: ERR No such master with that name. channel: [id: 0x2d66827d, L:/172.23.9.103:46812 - R:/172.24.107.11:26379] command: (SENTINEL SLAVES), params: [mymaster] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:365) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:196) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:134) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:104) ~[redisson-3.13.3.jar:3.13.3] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] 解决方法
最新发布
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值