温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Netty客户端接入流程NioSocketChannel怎么创建

发布时间:2022-03-28 09:21:29 来源:亿速云 阅读:176 作者:小新 栏目:开发技术

这篇文章主要为大家展示了“Netty客户端接入流程NioSocketChannel怎么创建”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Netty客户端接入流程NioSocketChannel怎么创建”这篇文章吧。

NioSocketChannel的创建

回到上一小节的read()方法

public void read() {     //必须是NioEventLoop方法调用的, 不能通过外部线程调用     assert eventLoop().inEventLoop();     //服务端channel的config     final ChannelConfig config = config();     //服务端channel的pipeline     final ChannelPipeline pipeline = pipeline();     //处理服务端接入的速率     final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();     //设置配置     allocHandle.reset(config);     boolean closed = false;     Throwable exception = null;     try {         try {             do {                 //创建jdk底层的channel                 //readBuf用于临时承载读到链接                 int localRead = doReadMessages(readBuf);                 if (localRead == 0) {                     break;                 }                 if (localRead < 0) {                     closed = true;                     break;                 }                 //分配器将读到的链接进行计数                 allocHandle.incMessagesRead(localRead);                 //连接数是否超过最大值             } while (allocHandle.continueReading());         } catch (Throwable t) {             exception = t;         }         int size = readBuf.size();         //遍历每一条客户端连接         for (int i = 0; i < size; i ++) {             readPending = false;             //传递事件, 将创建NioSokectChannel进行传递             //最终会调用ServerBootstrap的内部类ServerBootstrapAcceptor的channelRead()方法             pipeline.fireChannelRead(readBuf.get(i));         }         readBuf.clear();         allocHandle.readComplete();         pipeline.fireChannelReadComplete();         //代码省略     } finally {         //代码省略     } }

我们继续剖析int localRead = doReadMessages(readBuf)这一部分逻辑

我们首先看readBuf

private final List<Object> readBuf = new ArrayList<Object>();

这里只是简单的定义了一个ArrayList, doReadMessages(readBuf)方法就是将读到的链接放在这个list中, 因为这里是NioServerSocketChannel所以这走到了NioServerSocketChannel的doReadMessage()方法

跟到doReadMessage()方法中:

protected int doReadMessages(List<Object> buf) throws Exception {     //根据当前jdk底层的serverSocketChannel拿到jdk底层channel     SocketChannel ch = javaChannel().accept();     try {         if (ch != null) {             //封装成一个NioSokectChannel扔到buf中             buf.add(new NioSocketChannel(this, ch));             return 1;         }     } catch (Throwable t) {         //代码省略     }     return 0; }

jdk底层相关的内容

首先根据jdk的ServerSocketChannel拿到jdk的Channel, 熟悉Nio的小伙伴应该不会陌生

封装成一个NioSokectChannel扔到Readbuf中

这里的NioSocketChannel是对jdk底层的SocketChannel的包装, 我们看到其构造方法传入两个参数, this代表当前NioServerSocketChannel, ch代表jdk的SocketChannel

我们跟到NioSocketChannel的构造方法中:

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

这里看到调用了父类构造方法, 传入两个参数, parent代表创建自身channel的, NioServerSocketChannel, socket代表jdk底层的socketChannel

跟到父类构造方法中

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

其中SelectionKey.OP_READ代表其监听事件是读事件

继续跟父类的构造方法:

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {     super(parent);     this.ch = ch;     this.readInterestOp = readInterestOp;     try {         //设置为非阻塞         ch.configureBlocking(false);     } catch (IOException e) {         //代码省略     } }

这里初始化了自身成员变量ch, 就是jdk底层的SocketChannel, 并初始化了自身的监听事件readInterestOp, 也就是读事件

ch.configureBlocking(false)这一步熟悉nio的小伙伴也不陌生, 就是将jdk的SocketChannel设置为非阻塞

我们继续跟到父类构造方法中:

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

这里初始化parent, 也就是创建自身的NioServerSocketChannel, 并为自身创建了唯一id

初始化unsafe, 我们跟到newUnsafe()方法中

由于此方法是NioEventLoop调用的, 所以会走到其父类AbstractNioByteChannel的newUnsafe()

跟到newUnsafe()中:

protected AbstractNioUnsafe newUnsafe() {     return new NioByteUnsafe(); }

这里创建了NioByteUnsafe对象, 所以NioSocketChannel对应的unsafe是NioByteUnsafe

继续往下跟, 我们看到其初始化了pipeline, 有关pipline的知识, 我们会在下一章节中讲到

回到NioSocketChannel中的构造方法:

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

同NioServerSocketChannel一样, 这里也初始化了一个Config属性, 传入两个参数, 当前NioSocketChannel自身和jdk的底层SocketChannel的socket对象

我们跟进其构造方法

private NioSocketChannelConfig(NioSocketChannel channel, Socket javaSocket) {     super(channel, javaSocket); }

同样, 这个类是NioSocketChannel的内部类

继续跟父类构造方法:

public DefaultSocketChannelConfig(SocketChannel channel, Socket javaSocket) {     super(channel);     if (javaSocket == null) {         throw new NullPointerException("javaSocket");     }     //保存当前javaSocket     this.javaSocket = javaSocket;     //是否禁止Nagle算法     if (PlatformDependent.canEnableTcpNoDelayByDefault()) {         try {             setTcpNoDelay(true);         } catch (Exception e) {         }     } }

这里保存了SocketChannel的socket对象, 并且默认的情况禁止了Nagle算法, 有关Nagle, 感兴趣的同学可以学习下相关知识

继续跟到父类构造方法中:

public DefaultChannelConfig(Channel channel) {     this(channel, new AdaptiveRecvByteBufAllocator()); }

又跟到到了我们熟悉的部分了, 也就是说, 无论NioServerSocketChannel和NioSocketChannel, 最后都会初始化DefaultChannelConfig, 并创建可变ByteBuf分配器, 我们之前小节对此做过详细剖析这里不再赘述。

以上是“Netty客户端接入流程NioSocketChannel怎么创建”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI