我是靠谱客的博主 坚定蜜粉,最近开发中收集的这篇文章主要介绍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很像呢?

在这里,和服务端不同的是,客户端是直接调用new产生NioSocketChannel,而服务端是通过反射的方式(为什么会是这样设计呢?new出来的对象我们无法访问其中的私有属性,但是通过反射出来的对象我们可以通过setAccessible()方法来访问其中的私有属性,前面我们要优化keySet,所以需要用到反射获取一些field?参考)。

 

一、调用父类构造函数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(这个ch就是之前我们javaChannel.accept()得到的channel);把我们之前创建的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()

这个congfigure就是设置tcp的一些连接参数。

从这个地方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算法

最后

以上就是坚定蜜粉为你收集整理的netty源码阅读之客户端新连接之创建NioSocketChannel的全部内容,希望文章能够帮你解决netty源码阅读之客户端新连接之创建NioSocketChannel所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部