zoukankan      html  css  js  c++  java
  • BIO、NIO、AIO随手笔记

    BIO是一个连接一个线程。
    NIO是一个请求一个线程。
    AIO是一个有效请求一个线程

    BIO:  同步阻塞

    通过TCP三次握手进行连接,  一个client对应一个server  通过一个线程进行处理    在linux中最大能同时处理2000个请求(一般情况下)

    客户端Socket   ---------- 服务端ServerSocket

    BIO模型图(图源网络,原出处不明):

    NIO:同步非阻塞

    NIO的本质就是避免原始的TCP建立连接使用3次握手的操作,减少连接的开销

    主要的有Buffer(缓冲区)、Channel(通道)、Selector(多路复用器)       

    Channel包含4个状态     连接(OP_CONNECT)、可读(OP_READ)、可写(OP_WRITE)、阻塞(OP_ACCEPT)

    该模型为  将多个channel注册到一个Selector上   然后通过一个线程对  Selector进行轮询 处理   Channel上的的状态

    NIO 第一次连接时也是用的TCP连接

    1. Buffer(ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBUffer、FloatBuffer、DoubleBUffer)

    2. 客户端SocketChannel---------服务端serverSocketChannel 

    3.  Selector

    
    

    伪异步IO模型图(图源网络,原出处不明):

    创建NIO服务器的主要步骤

        (1)打开ServerSocketChannel,监听客户端连接

        (2)绑定监听端口,设置连接为非阻塞模式

        (3)创建Reactor线程,创建多路复用器并启动线程

         (4)将ServerSocketChannel注册到Reactor线程中的Selector上,监听ACCEPT事件

         (5)Selector轮询准备就绪的key

         (6)Selector监听到新的客户端接入,处理新的接入请求,完成TCP三次握手,简历物理链路

         (7)设置客户端链路为非阻塞模式

         (8)将新接入的客户端连接注册到Reactor线程的Selector上,监听读操作,读取客户端发送的网络消息

         (9)异步读取客户端消息到缓冲区

         (10)对Buffer编解码,处理半包消息,将解码成功的消息封装成Task

         (11)将应答消息编码为Buffer,调用SocketChannel的write将消息异步发送给客户端

    NIO 原理图:

    代码启动时要先启动 Server端 再启动Client端

    代码  Client端

    public class NioClient {

    private final static String ip = "localhost";
    private final static int port = 8081;
    private Selector selector;

    private void innit() throws IOException {

    //1. 首先创建一个客户端的 socket 通道
    SocketChannel channel = SocketChannel.open();
    // 设置通道为非阻塞 TODO
    channel.configureBlocking(false);
    // 打开一个 多路复用器(通道管理器)
    selector = Selector.open();
    // 连接通道
    channel.connect(new InetSocketAddress(ip, port));
    // 将channel 注册到通道管理器上 并且设置当前通道的key为 连接
    channel.register(selector, SelectionKey.OP_CONNECT);

    }

    private void listen() throws IOException {

    while (true) {
    selector.select();
    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    while (iterator.hasNext()) {
    SelectionKey key = iterator.next();
    // 删除已选的key,以防重复处理
    iterator.remove();
    // 如果是连接的时候
    if (key.isConnectable()) {
    // 获取当前的channel
    SocketChannel socketChannel = (SocketChannel) key.channel();
    // 如果是正在连接 则进行连接
    if (socketChannel.isConnectionPending()) {
    socketChannel.finishConnect();
    }

    // 设置成非阻塞 TODO
    socketChannel.configureBlocking(false);
    Scanner scanner = new Scanner(System.in);
    System.out.println("ScannerTest, Please Enter Name:");
    String name = scanner.nextLine();
    socketChannel.write(ByteBuffer.wrap(("To Server:" + name).getBytes()));

    socketChannel.register(selector, SelectionKey.OP_READ);
    }

    if (key.isReadable()) {
    // 进行读取的操作
    }

    }


    }

    }

    public static void main(String[] args) throws IOException {
    NioClient nioClient = new NioClient();
    nioClient.innit();
    nioClient.listen();

    }

    }


    Server端:
    public class NioServer {

    private final static int port = 8081;

    private Selector selector;

    private void init(int port) {
    try {
    // 开启服务端的 socket
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    // 设置通道为非阻塞
    serverSocketChannel.configureBlocking(false);
    // 将该通道绑定到端口上
    serverSocketChannel.socket().bind(new InetSocketAddress(port));
    // 开启多路复用器
    selector = Selector.open();
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

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

    private void listen() throws IOException {
    System.out.println("服务端启动成功");
    while (true) {
    //当注册的事件到达时,方法返回;否则,该方法会一直阻塞
    selector.select();
    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    while (iterator.hasNext()) {
    SelectionKey key = iterator.next();
    // 防止重复处理
    iterator.remove();
    // 客户端请求连接事件
    if (key.isAcceptable()) {
    System.out.println("进入客户端连接····");
    // 获取的是server端口的 通道
    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
    // 获取和客户端的链接 TODO
    SocketChannel socketChannel = serverSocketChannel.accept();
    // 设置成非阻塞
    socketChannel.configureBlocking(false);

    // socketChannel.write(ByteBuffer.wrap(new String("To Client:22222222").getBytes()));
    // 将获取到客户端的通道注册到 多路复用器上
    socketChannel.register(selector,SelectionKey.OP_READ);
    }
    if (key.isReadable()) {
    read(key);
    }

    }
    }
    }

    private void read(SelectionKey key) throws IOException {
    // 服务器可读取消息:得到事件发生的Socket通道
    SocketChannel channel = (SocketChannel) key.channel();
    // 创建buffer 缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    channel.read(buffer);
    byte[] array = buffer.array();
    System.out.println("服务端收取到消息" + new String(array));

    }

    public static void main(String[] args) throws IOException {
    NioServer nioServer = new NioServer();
    nioServer.init(port);
    nioServer.listen();
    }

    }

    AIO: 异步非阻塞

    在java1.7后才实现了 异步非阻塞

    AIO编程,在NIO基础之上引入了异步通道的概念。并提供异步文件和异步套接字通道的实现,从而在真正意义上实现了异步非阻塞,之前我们学过的NIO只是非阻塞而非异步。而AIO它不需要通过多路复用器对注册的通道的进行轮训操作即可实现异步读写,从而简化了NIO编程模型。也可以称为NIO2.0,这种模式才是真正的属于异步非阻塞的模型。

     

    AsynchronousServerScoketChannel

    AsynchronousScoketChanel

  • 相关阅读:
    FCK常用Js,获取FCK内容,统计FCK字数,向FCK写入指定代码
    asp 点击链接 下载图片文件
    使用微软的 Visual Studio International Pack 1.0 进行网站简体与繁体的互转和得到汉字、拼音、笔画
    mysql alter 语句用法,添加、修改、删除字段等
    C#指定窗口显示位置的方法
    Soukey采集软件源码
    [转](收藏)《博客园精华集》分类索引
    YUI CSS Foundation讲座 博客文库 博客园
    sql group by 和having
    sql 多表查询
  • 原文地址:https://www.cnblogs.com/zgxz/p/14133657.html
Copyright © 2011-2022 走看看