ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

netty(二)从BIO至NIO的演进

2022-05-01 22:04:55  阅读:166  来源: 互联网

标签:netty NIO BIO 线程 new 客户端 服务端 String


一、传统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();
    }
}

执行效果及思考

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

  • 1、线程资源受限:同一时刻大量线程阻塞等待读取数据,资源浪费。
  • 2、线程切换效率底下:如果上述代码在多客户端的情况下,每个客户端都需要单独开一个线程,则在系统中来回切换线程的成本也直线上升。
  • 3、读写受限:以字节流的方式读取,数据需要自己缓存且不可重复读取。

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

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

1、线程资源受限

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

2、线程切换效率低下

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

3、读写受限

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

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

三、NIO的实现思路

  • 1、NIO中通常会有2个线程,每个线程绑定1个轮询器selector。【 1个用于轮询是否有新链接,另1个用于轮询是否有数据可读】
  • 2、Server端获取到新链接后,直接将其绑定到负责读取数据的selector上。【这样就不用每次新连接来了都开个线程来监听,极大的减少了线程数】
  • 3、读数据的selector被死循环包着,若某一时刻有多个链接有数据可读,则批量取出来进行处理

四、主角登场!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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有