zoukankan      html  css  js  c++  java
  • netty权威指南学习笔记一——NIO入门(1)BIO

      公司的一些项目采用了netty框架,为了加速适应公司开发,本博主认真学习netty框架,前一段时间主要看了看书,发现编程这东西,不上手还是觉得差点什么,于是为了加深理解,深入学习,本博主还是决定多动手,一方面记录一些总结性的思考性东西,另一方面也为日后复习查看留下一些东西。

      那么废话少说,现在开始,首先在进入netty学习之前,我们是要认识一下IO并引出NIO的概念。

      与IO相关的几种编程及特点分为:

    编程类别 特点
    传统BIO编程

    典型的一请求一应答模型,一个请求新建一个线程,应答完成线程销毁,线程个数和客户端并发访问呈现1:1的正比关系,当线程数膨胀之后,虚拟机性能下降明显,随着并发量继续增大,线程耗尽就会出现线程堆栈溢出,创建新线程失败,并最终宕机。该模型无法满足高性能高并发的场景。

    伪异步IO编程

    伪异步IO是对BIO的优化,引入线程池和消息队列,改善了传统BIO编程,但是其底层仍然是BIO模型,该模型引入线程池后界定了线程的数量,N个线程处理M个客户端请求,M可以远远大于N,线程池灵活调配线程资源,有最大线程数限制,避免了一个客户端请求创建一个线程的弊端,不会发生高并发访问下的线程资源耗尽而造成堆栈溢出或宕机的问题。

    其不利因素是当一个客户端请求没有处理完成时,如IO读写或网络慢时,会造成任务队列中的任务一直处于等待状态,被阻塞了。当线程池中所有线程都满程处于阻塞状态时,就无法接收客户端新的请求,请求总是超时,此时可以认为是系统崩溃。

    NIO编程

    NIO模型引入了缓冲区Buffer,所有数据的读写都是用缓冲区处理的。引入channel通道,和selector多路复用器。

    客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞,

    socketchannel的读写都是一步的,如果没有可以读写的数据他不会同步等待,直接返回,这样I/O通信线程就可以处理其他的链路,不需要同步等待这个链路可用;

    Selector线程可以同时处理成千上万个客户端连接,而且性能不会随客户端的增加而线性下降,非常适合高性能、高负载的网络服务器。

    AIO编程

    AIO是NIO2.0,它引入了异步通道概念,提供了异步文件通道和异步套接字通道的实现。异步通道提供了java.util.concurrent.Future类来表示异步操作的结果。

    在执行异步操作时候传入一个java.io.channels.

    CompletionHandler接口的实现类作为操作完成的回调。

    NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它不需要通过多路复用器Selector对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。

    现在看看逐个看看相关模型和代码:

    BIO模型

    传统的BIO代码 时间服务端

    package com.example.biodemo;
    
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TimeServer {
        public static void main(String[] args) throws IOException {
            int port = 8090;
            if (args != null && args.length > 0) {
                try {
                    port = Integer.valueOf(args[0]);
                } catch (NumberFormatException e) {
                    port = 8090;
                }
            }
            ServerSocket server = null;
            try {
                server = new ServerSocket(port);
                System.out.println("the timeServer is start in port :" + port);
                Socket socket = null;
                while (true) {
                    socket = server.accept();
                    new Thread(new TimeServerHandler(socket)).start();
                }
            } finally {
                if (server != null) {
                    System.out.println("the time server close");
                    server.close();
                    server = null;
                }
            }
    
        }
    }
    

    传统BIO 时间处理

    package com.example.biodemo;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class TimeServerHandler implements Runnable {
        private Socket socket;
    
        public TimeServerHandler(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedReader in = null;
            PrintWriter out = null;
            try {
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                out = new PrintWriter(this.socket.getOutputStream(), true);
                String currentTime = null;
                String body = null;
                while (true) {
                    body = in.readLine();
                    if (body == null) {
                        break;
                    }
                    System.out.println("the time server receive order:" + body);
                    currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "bad order";
                    out.println(currentTime);
    
                }
            } catch (Exception e) {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException el) {
                        el.printStackTrace();
                    }
                }
                if (out != null) {
                    out.close();
                    out = null;
                }
                if (this.socket != null) {
                    try {
                        this.socket.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    this.socket = null;
                }
            }
        }
    }
    

      客户端代码

     1 package com.example.biodemo;
     2 
     3 import java.io.*;
     4 import java.net.Socket;
     5 
     6 public class TimeClient {
     7     public static void main(String[] args) {
     8         int port = 8090;
     9         if (args != null && args.length > 0) {
    10             try {
    11                 port = Integer.valueOf(args[0]);
    12             } catch (NumberFormatException ne) {
    13                 port = 8090;
    14             }
    15         }
    16         Socket socket = null;
    17         BufferedReader in = null;
    18         PrintWriter out = null;
    19         try {
    20             socket = new Socket("127.0.0.1", port);
    21             System.out.println(socket.getInputStream());
    22             in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    23             out = new PrintWriter(socket.getOutputStream(), true);
    24             out.println("QUERY TIME ORDER");
    25             System.out.println("send order 2 server succeed.");
    26             String resp = in.readLine();
    27             System.out.println("now is :" + resp);
    28         } catch (IOException e1) {
    29 
    30         } finally {
    31             if (out != null) {
    32                 out.close();
    33                 out = null;
    34             }
    35 
    36             if (in != null) {
    37                 try {
    38                     in.close();
    39                 } catch (IOException e2) {
    40                     e2.printStackTrace();
    41                 }
    42                 in = null;
    43                 if (socket != null) {
    44                     try {
    45                         socket.close();
    46                     } catch (IOException e3) {
    47                         e3.printStackTrace();
    48                     }
    49 
    50                 }
    51                 socket = null;
    52             }
    53 
    54 
    55         }
    56     }
    57 }

    启动服务端

    启动客户端

    再看看服务端

    整个过程是:服务端先在某一端口启动服务,本博主是在8090上启动,启动后,客户端启动,发送请求,请求被服务端接收后,进行逻辑处理,并将逻辑处理结果返回,这里的逻辑处理结果是当前时间,返回的结果客户端接收后显示出来。这就是一个典型的BIO模型。

  • 相关阅读:
    未来房价经济管窥(崩溃不行,疯涨也不行,所以只能冰冻。房产税的开征是个关键转折点,也是判断未来房价的重要指标。大城市的房租还会继续涨,以后不愁没房子住,虽然仍然买不起)
    QT使用UAC(经过验证)
    ALT+数字,可输入汉字或拉丁字母 good
    RUST叫系统编程语言,而GO是网络编程语言
    最近学习了下BI(商业智能)做报表
    选择优势股票,动态配置
    对加密方式(公钥私钥)的形象理解(以http和https为例)
    SQLServer重建索引
    怎么样成为一个全栈程序员(请把一个能力发展到90,如果你还有余力把另一个能力发展到90,否则就是平庸的废材)
    如何才能学到Qt的精髓——信号槽之间的无关性,提供了绝佳的对象间通讯方式,QT的GUI全是自己的一套,并且完全开源,提供了一个绝好机会窥视gui具体实现
  • 原文地址:https://www.cnblogs.com/xiaoyao-001/p/9276978.html
Copyright © 2011-2022 走看看