其他分享
首页 > 其他分享> > netty(二)从BIO至NIO的演进

netty(二)从BIO至NIO的演进

作者:互联网

一、传统BIO实现对话的例子

Server服务端

/**
 * BIO服务端
 *
 * @author 有梦想的肥宅
 * @date 2022/5/1
 */
public class BIOServer {
    public static void main(String[] args) throws Exception {
        //1、创建一个服务端的套接字,监听8000端口
        ServerSocket serverSocket = new ServerSocket(8000);

        //2、创建线程去接收新的连接
        new Thread(() -> {
            while (true) {
                try {
                    //2.1 阻塞方法获取新连接
                    Socket socket = serverSocket.accept();

                    //3、为每一个新连接都创建线程,负责读取数据
                    new Thread(() -> {
                        try {
                            int len;
                            byte[] data = new byte[1024];
                            InputStream inputStream = socket.getInputStream();
                            //3.1 按字节流方式读取数据
                            while ((len = inputStream.read(data)) != -1) {
                                System.out.println(new String(data, 0, len));
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }).start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

Client客户端

/**
 * BIO客户端
 *
 * @author 有梦想的肥宅
 * @date 2022/5/1
 */
public class BIOClient {
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                //1、连接127.0.0.1:8000端口
                Socket socket = new Socket("127.0.0.1", 8000);
                while (true) {
                    try {
                        //2、每间隔2秒向服务端发一个请求,输出一句话
                        socket.getOutputStream().write((new Date() + ": Hello有梦想的肥宅~").getBytes(StandardCharsets.UTF_8));
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
}

执行效果及思考

  执行效果如上图,是能实现我们的效果了,但是我们思考一下,这样的程序有什么问题?

  为了解决这些问题,JDK1.4之后推出NIO的实现,但由于原生的NIO实现非常复杂且容易出错,我们简单了解下它的实现思路以及如何解决上面3个问题即可,毕竟我们是要学习更轻便的netty~

二、NIO的出现如何解决上述3个问题呢?

1、线程资源受限

  从上面两张图片对比我们可以看出,BIO到NIO的转变少创建了非常多的线程,主要由于引入了selector的机制来管理我们的链接,系统内存在的死循环线程数一下子就降低了几个量级,也就突破了线程资源受限的瓶颈。

2、线程切换效率低下

  由于NIO模型中的线程数量大大降低,因此线程切换效率也大幅提高。

3、读写受限

  BIO读写:面向,一次只能从流中读取一个或多个字节,读完后无法再次读取,需自己缓存数据。

  NIO读写:面向Buffer,可随意读取任何字节数据,且不需要自己缓存数据。

三、NIO的实现思路

四、主角登场!Netty横空出世~

  简介:Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务端和客户端。

  通俗:封装了JDK的NIO,让我们用得更方便~

maven依赖

<!--Netty-->
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
  <version>4.1.6.Final</version>
</dependency>

服务端

/**
 * Netty实现的NIO服务端
 *
 * @author 有梦想的肥宅
 * @date 2022/5/1
 */
public class NettyNIOServer {
    public static void main(String[] args) {
        //1、创建服务端启动引导类,用于引导服务端的启动工作
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //2、创建NioEventLoopGroup对象,作用类似线程组
        NioEventLoopGroup boss = new NioEventLoopGroup();//用于获取链接的线程组
        NioEventLoopGroup worker = new NioEventLoopGroup();//用于获取数据的线程组

        //3、配置服务端启动引导类
        serverBootstrap
                .group(boss, worker)//3.1 配置两大线程组
                .channel(NioServerSocketChannel.class)//3.2 配置NIO模型
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    //3.3 定义每个链接的数据读写逻辑
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        //PS:数据在网络中以字节传输,我们无法直接传输String对象,需要添加String的编码解码器
                        ch.pipeline().addLast(new StringDecoder());//把网络字节流自动解码为String对象,属于入站处理器
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                                System.out.println(msg);
                            }
                        });
                    }
                }).bind(8000);//3.4 绑定8000端口
    }
}

客户端

/**
 * Netty实现的NIO客户端
 *
 * @author 有梦想的肥宅
 * @date 2022/5/1
 */
public class NettyNIOClient {
    public static void main(String[] args) throws InterruptedException {
        //1、创建客户端启动引导类,用于引导客户端的启动工作和连接服务端
        Bootstrap bootstrap = new Bootstrap();

        //2、创建NioEventLoopGroup对象,作用类似线程组
        NioEventLoopGroup group = new NioEventLoopGroup();

        //3、配置客户端启动引导类
        bootstrap
                .group(group)//3.1 指定线程模型
                .channel(NioSocketChannel.class) //3.2 配置NIO模型
                .handler(new ChannelInitializer<Channel>() {
                    //3.3 定义每个链接的数据读写逻辑
                    @Override
                    protected void initChannel(Channel ch) {
                        //PS:数据在网络中以字节传输,我们无法直接传输String对象,需要添加String的编码解码器
                        ch.pipeline().addLast(new StringEncoder());//对String对象自动编码,属于出站处理器
                    }
                });

        //4、与服务端建立连接
        Channel channel = bootstrap.connect("127.0.0.1", 8000).channel();

        //5、向服务端输出数据
        while (true) {
            channel.writeAndFlush(new Date() + ": Hello有梦想的肥宅~");
            Thread.sleep(2000);
        }
    }
}

执行效果及思考

  由上图可以看到执行效果和BIO是一致的,但是执行效率却是天差地别!【BIO只能承载最多数十个客户端,而Netty(NIO)实现的并发量非常大!

  另外一点,Netty对JDK中的NIO也做了非常好的封装,从代码量也可以看出只需要几行代码即可完成服务端或者客户端的功能了~(有兴趣的小伙伴可以去对比下原生NIO的代码,相当可怕~)

标签:netty,NIO,BIO,线程,new,客户端,服务端,String
来源: https://www.cnblogs.com/riches/p/16213563.html