zoukankan      html  css  js  c++  java
  • 网络IO模型

    1、同步网络IO模型

      

       网络IO模型分两段,一个write,一个read,write操作我们不需要考虑,这里我们看read操作。

    接受线程会一直阻塞,当有数据到来的时候,操作系统会先把数据写入接收缓存,然后给接收数据的线程发一个通知,

    线程收到通知后结束等待,开始读取数据。处理完这一批数据后,继续阻塞等待下一批数据到来,这样周而复始地处理收到的数据。

      每个连接都需要阻塞一个线程来等待数据,当大量连接数时就会有大量线程被阻塞,造成CPU负载过高,系统的性能较慢

    2、异步网络模型

      同步IO导致线程阻塞会影响性能,同时也不能使用极少的线程来处理网络请求,所以我们想到异步网络模型。脑海中想到系统异步设计中,采用非阻塞的模式,当有数据来的时候创建一个线程

    来接收数据,这样就可以用少量的线程来处理大量的连接。

      

        1、使用Netty实现网络通信

          

    // 创建一组线性
    EventLoopGroup group = new NioEventLoopGroup();
    
    try{
        // 初始化Server
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(group);
        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));
    
        // 设置收到数据后的处理的Handler
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(new MyHandler());
            }
        });
        // 绑定端口,开始提供服务
        ChannelFuture channelFuture = serverBootstrap.bind().sync();
        channelFuture.channel().closeFuture().sync();
    } catch(Exception e){
        e.printStackTrace();
    } finally {
        group.shutdownGracefully().sync();
    }

      首先我们创建了一个 EventLoopGroup 对象,命名为 group,这个 group 对象你可以简单把它理解为一组线程。这组线程的作用就是来执行收发数据的业务逻辑。然后,使用 Netty 提供的 ServerBootstrap 来初始化一个 Socket Server,绑定到本地 9999 端口上。在真正启动服务之前,我们给 serverBootstrap 传入了一个 MyHandler 对象,这个 MyHandler 是我们自己来实现的一个类,它需要继承 Netty 提供的一个抽象类:ChannelInboundHandlerAdapter,在这个 MyHandler 里面,我们可以定义收到数据后的处理逻辑。这个设置 Handler 的过程,就是我刚刚讲的,预先来定义回调方法的过程。最后就可以真正绑定本地端口,启动 Socket 服务了。

      Netty是全自动的处理,只需要我们维护接收数据后的回调函数即可。像线程控制、缓存管理、连接管理都不需要操心。具体实现:当接收到客户端的数据后,netty会在EventLoopGroup中获取一个IO线程

    在这个IO线程中调用执行业务逻辑的回调方法。

        2、使用NIO

        NIO即IO多路复用,复用一个线程处理多个网络连接。他提供selector对象,,每个已经建立好的连接用一个 Channel 对象来表示。我们希望能实现,在一个线程里,接收来自多个 Channel 的数据。也就是说,这些 Channel 中,任何一个 Channel 收到数据后,第一时间能在同一个线程里面来处理。

        

       Selecor 通过一种类似于事件的机制来解决这个问题。首先你需要把你的连接,也就是 Channel 绑定到 Selector 上,然后你可以在接收数据的线程来调用 Selector.select() 方法来等待数据到来。这个 select 方法是一个阻塞方法,这个线程会一直卡在这儿,直到这些 Channel 中的任意一个有数据到来,就会结束等待返回数据。它的返回值是一个迭代器,你可以从这个迭代器里面获取所有 Channel 收到的数据,然后来执行你的数据接收的业务逻辑。

      关于java网络模型的比喻:

      例子:有一个养鸡的农场,里面养着来自各个农户(Thread)的鸡(Socket),每家农户都在农场中建立了自己的鸡舍(SocketChannel)
        1、BIO:Block IO,每个农户盯着自己的鸡舍,一旦有鸡下蛋,就去做捡蛋处理;
        2、NIO:No-Block IO-单Selector,农户们花钱请了一个饲养员(Selector),并告诉饲养员(register)如果哪家的鸡有任何情况(下蛋)均要向这家农户报告(select keys);
        3、NIO:No-Block IO-多Selector,当农场中的鸡舍逐渐增多时,一个饲养员巡视(轮询)一次所需时间就会不断地加长,这样农户知道自己家的鸡有下蛋的情况就会发生较大的延迟。怎么呢?、  没错,多请几个饲养员(多Selector),每个饲养员分配管理鸡舍,这样就可以减轻一个饲养员的工作量,同时农户们可以更快的知晓自己家的鸡是否下蛋了;
        4、Epoll模式:如果采用Epoll方式,农场问题应该如何改进呢?其实就是饲养员不需要再巡视鸡舍,而是听到哪间鸡舍的鸡打鸣了(活跃连接),就知道哪家农户的鸡下蛋了;
        5、AIO:Asynchronous I/O, 鸡下蛋后,以前的NIO方式要求饲养员通知农户去取蛋,AIO模式出现以后,事情变得更加简单了,取蛋工作由饲养员自己负责,然后取完后,直接通知农户来拿即可,而不需要农户自己到鸡舍去取蛋。

  • 相关阅读:
    郎咸平 马行空 - 郎咸平说:萧条下的希望(2014年10月25日)
    豆豆 - 遥远的救世主(2014年10月18日)
    高铭 - 天才在左 疯子在右(2014年10月3日)
    张庭斌 艾经纬 - 中国富人为何变穷:金融危机攻略(2014年5月20日)
    王晋康 - 终极爆炸 ▪ 王晋康科幻小说精选集3(2014年4月24日)
    刘慈欣 - 乡村教师 ▪ 刘慈欣科幻自选集(2014年4月2日)
    王晋康 - 替天行道 ▪ 王晋康科幻小说精选集2(2014年3月27日)
    易之 - 我是个算命先生(2014年3月23日)
    宋鸿兵 - 货币战争5(2014年3月20日)
    【英】阿瑟 ▪ 克拉克 - 神的九十九亿个名字(2014年3月16日)
  • 原文地址:https://www.cnblogs.com/volare/p/12292291.html
Copyright © 2011-2022 走看看