当前位置: 首页 > news >正文

netty编程之对3种IO模式的支持以及对应的关键源码分析

写在前面

本文看下netty对常见的3种IO模式的支持。

1:IO模式对应的类

netty对Java种的3种IO模式都进行了支持,主要类的如下:
在这里插入图片描述

2:netty切换3种IO模式源码分析

因为对于aio的支持已经remove,所以这里不再分析,望周知!!!

在前面我们分析了Java有三种io模式,分别是BIO阻塞IO模式,NIO new io模式,AIO 异步IO模式,在netty中对这三种都进行了良好的支持,并且为了简化用户的切换和使用,在设计上也是下足了一番功夫。
不管是哪种Java io模式,都有如下的几部分内容需要我们指定:

线程模型:对应的接口是EventLoopGroup,对应的不同线程模型实现类有其特定的前缀,比如NIO就是NioEventLoopGroup,Oio就是OioEventLoopGroup。
IO模式:服务监听类对应的接口是ServerChannel,如NIO就是NioServerSocketChannel,Oio就是OioServerSocketChannel。数据读写类对应的接口是io.netty.channel.socket.SocketChannel,如NIO就是NioSocketChannel,bio就是OioSocketChannel

可参考下图:
在这里插入图片描述

所以,这里我们切换不同的Java io模式的实现就是修改netty中对应的线程模型和io模式实现类就行了,如下是基于nio模式实现的一个echo server:

/** Copyright 2012 The Netty Project** The Netty Project licenses this file to you under the Apache License,* version 2.0 (the "License"); you may not use this file except in compliance* with the License. You may obtain a copy of the License at:**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the* License for the specific language governing permissions and limitations* under the License.*/
package com.dahuyou.netty.huohuo;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;/*** Echoes back any received data from a client.*/
public final class EchoServer {static final boolean SSL = System.getProperty("ssl") != null;static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));public static void main(String[] args) throws Exception {// Configure SSL.final SslContext sslCtx;if (SSL) {SelfSignedCertificate ssc = new SelfSignedCertificate();sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();} else {sslCtx = null;}// Configure the server.// Java nio模式下的线程模型类EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();final EchoServerHandler serverHandler = new EchoServerHandler();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // java nio 模式下具体io模式类.option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();if (sslCtx != null) {p.addLast(sslCtx.newHandler(ch.alloc()));}//p.addLast(new LoggingHandler(LogLevel.INFO));p.addLast(serverHandler);}});// Start the server.ChannelFuture f = b.bind(PORT).sync();// Wait until the server socket is closed.f.channel().closeFuture().sync();} finally {// Shut down all event loops to terminate all threads.bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

为了确定其echo功能是好使的,先来运行测试下:
在这里插入图片描述
这里我们以切换到bio模式(netty中叫Oio,所以相关类是以Oio打头的,要注意下)为例看下如何修改代码,首先线程模型EventLoopGroup:
在这里插入图片描述
修改IO模式类:
在这里插入图片描述
这样就可以了,接着来运行测试下:
在这里插入图片描述

那么,netty是怎么做到的呢?对线程模型没什么好说的,因为直接修改了所创建的对象类型,那么对于io模式只是指定了class类型,怎么就切换了呢?主要看代码.channel(NioServerSocketChannel.class),源码如下:

// io.netty.bootstrap.AbstractBootstrap#channel
public B channel(Class<? extends C> channelClass) {if (channelClass == null) {throw new NullPointerException("channelClass");}return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}// io.netty.channel.ReflectiveChannelFactory#ReflectiveChannelFactory
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {public ReflectiveChannelFactory(Class<? extends T> clazz) {ObjectUtil.checkNotNull(clazz, "clazz");try {this.constructor = clazz.getConstructor();} catch (NoSuchMethodException e) {throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +" does not have a public non-arg constructor", e);}}// 该方法通过设置直接创建对应的实例@Overridepublic T newChannel() {try {return constructor.newInstance();} catch (Throwable t) {throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);}}
}

所以io模式对应的类是通过工厂方式基于反射来完成动态创建的。其中方法newChannel()返回的具体通道类型泛型T通过类中指定,也就是.channel(NioServerSocketChannel.class)指定的类型,这个确定泛型类型的过程如下:
在这里插入图片描述
所以netty通过泛型+工厂模式+反射实现了不同io模式的切换工作,使用还是非常简单的,这就是一个典型的优秀的设计,在工作中如果有类似的场景也要抄起来,能抄也是水平啊。
最后,读写消息的socketchannel我们并没有指定,这是怎么回事呢?这是因为在serversocketchannel会负责该类的创建,也就是不需要我们显式的来指定:

// io.netty.channel.socket.nio.NioServerSocketChannel#doReadMessages
public class NioServerSocketChannel extends AbstractNioMessageChannelimplements io.netty.channel.socket.ServerSocketChannel {@Overrideprotected int doReadMessages(List<Object> buf) throws Exception {SocketChannel ch = SocketUtils.accept(javaChannel());}public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {try {return AccessController.doPrivileged(new PrivilegedExceptionAction<SocketChannel>() {@Overridepublic SocketChannel run() throws IOException {// 这里就完成socketchannel的创建了,是jdk中Java nio的方法,大家应该比较熟悉了return serverSocketChannel.accept();}});} catch (PrivilegedActionException e) {throw (IOException) e.getCause();}}
}

代码serverSocketChannel.accept();就完成socketchannel的创建了,是jdk中Java nio的方法,大家应该比较熟悉了。

写在后面

参考文章列表


http://www.mrgr.cn/news/36761.html

相关文章:

  • yolov5/v7/v8随机种子固定方法
  • 电脑usb接口封禁如何实现?5种禁用USB接口的方法分享!(第一种你GET了吗?)
  • 【已解决】Ubuntu 24.04 修改 ssh 连接端口无效
  • BSIM4 and MOSFET Modeling For IC Simulation
  • 屏幕翻译下载哪个?建议试试这5个
  • 【Golang】Go语言中type关键字到底是什么?
  • 遥感图像语义分割数据集制作(使用ArcGIS Pro)
  • 如何更改发票校验行项目布局
  • Java数据结构--List介绍
  • python功能测试
  • 不同类型的专利有哪些特点和区别?
  • 数据结构练习题————(二叉树)——考前必备合集!
  • 单片机项目合集列表与专栏说明——Excel合集列表目录查阅(持续更新)
  • 猜想的反例:DFS中结点顺序与后代关系的分析
  • GPT2模型源码解析
  • 静态多态和动态多态
  • cross apply 和 outer apply 的区别
  • Redis相关知识
  • docker(一)之cgroup详解
  • Excel怎么自动排序?4种方法任君选择