netty源码阅读之客户端新连接之创建NioSocketChannel

创建NioSocketChannel其实和创建服务端的NioServerSocketChannel类似,从上一篇文章的new NioSocketChannel(this, ch)这里进入,主要做了两件事:

1、调用父类构造函数AbstractNioByteChannel(p,ch,op_read)

1)设置configureBlocking(false),并且把传进来的op_read 保存起来

2)create id,unsafe,pipeline

2、新建new NioSocketChannelConfig()

主要是调用了这个函数setTcpNoDelay(true)

源码如下:

    public NioSocketChannel(Channel parent, SocketChannel socket) {
        super(parent, socket);
        config = new NioSocketChannelConfig(this, socket.socket());
    }

是不是和创建服务端NioServerSocketChannel很像呢?

一、调用父类构造函数AbstractNioByteChannel(p,ch,op_read)

先看调用父类的构造方法:

protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
        super(parent, ch, SelectionKey.OP_READ);
    }

这里注意了,直接产生了一个OP_READ事件进去。因为这个是客户端的,所以客户端只用读事件,如果是服务端,那就是OP_ACCEPT事件。然后继续进入:

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            ch.configureBlocking(false);
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {
                if (logger.isWarnEnabled()) {
                    logger.warn(
                            "Failed to close a partially initialized socket.", e2);
                }
            }

            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }

this.ch = ch;把我们之前创建的jdk的socketChannel绑定到我们的这个服务端SocketChannel这里,并且把刚刚创建的readInterestOps事件也传入了进来。

下面有一个ch.configureBlocking(false)就是设置非阻塞模式。

我们还要继续从super(parent);进入:

protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }

如果是客户端的NioSocketChannel,会有一个parent,就是我们服务端NioServerSocketChannel

id不用说了,这个unsafe就是NioSocketChannel用来负责处理底层该数据的读写。NioServerSocketChannel的实现是NioMessageUnsafe,而NioSocketChannel的实现是NioByteUnsafe,因为服务端处理的事件是连接时间,而客户端处理的是读事件,所以有所不同。

pipeline就是处理逻辑链,后面的文章会继续深入。

二、新建new NioSocketChannelConfig()

从这个地方config = new NioSocketChannelConfig(this, socket.socket());进入:

  public DefaultSocketChannelConfig(SocketChannel channel, Socket javaSocket) {
        super(channel);
        if (javaSocket == null) {
            throw new NullPointerException("javaSocket");
        }
        this.javaSocket = javaSocket;

        // Enable TCP_NODELAY by default if possible.
        if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
            try {
                setTcpNoDelay(true);
            } catch (Exception e) {
                // Ignore.
            }
        }
    }

找到setTcpNoDelay这个方法进去

    @Override
    public SocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
        try {
            javaSocket.setTcpNoDelay(tcpNoDelay);
        } catch (SocketException e) {
            throw new ChannelException(e);
        }
        return this;
    }

这里就是调用jdk底层不使用Nagle算法。关于这个算法:为了提高吞吐量,把小数据包集合成大数据包一起发过去。

但是这样会提高延时,netty默认设置了禁用此算法,可以降低延时。

看这个方法PlatformDependent.canEnableTcpNoDelayByDefault()的实现:

public static boolean canEnableTcpNoDelayByDefault() {
    return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
}
private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid();

也就是,当不是安卓的时候,就设置优化。另外一个细节就是,netty居然也支持安卓。

关于Nagle算法

猜你喜欢

转载自blog.csdn.net/fst438060684/article/details/81586156
今日推荐