• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

java IO模型和NIO编程

武飞扬头像
weixin_38137717
帮助5

java IO模型及NIO编程

1.1java支持的网络模型

  • BIO(同步阻塞IO)
  • NIO(同步非阻塞IO)
  • AIO(异步IO)

1.2.阻塞和非阻塞区别

主要指的是访问IO的线程是否会阻塞(或处于等待)
线程访问资源,该资源是否准备就绪的一种处理方式

比如当线程获取资源B之前必须先等待获取资源A,等待A获取完毕后才能进行操作则为阻塞,否则为非阻塞
学新通

1.3.同步和异步区别

主要是获取数据的方式,同步异步是等待数据返回,异步异步采用回调,处理完毕通知的方式

1.4.BIO(同步并阻塞IO)

Java BIO就是传统的 socket编程.

BIO(blocking I/O) : 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器
端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程
池机制改善(实现多个客户连接服务器)。

1.4.1.模型图

学新通

1.4.2.BIO存在的缺点
  • 每个请求都需要创建独立的线程,与对应的客户端进行数据 Read,业务处理,数据 Write
  • 并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
  • 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费

1.5. NIO(同步非阻塞)

同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到
多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理

学新通

1.6 AIO(异步非阻塞)

AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的
特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长
的应用

AIO采用异步通知的方式,如事件驱动,当有操作时主动通知服务器。

2.NIO编程

2.1NIO三大核心知识
  1. Channel(通道)

  2. Buffer(缓存) 面向缓冲区进行编程,可以

  3. Selector(选择器)

    Java NIO 的非阻塞模式 。使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的
    数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可
    以读取之前,该线程可以继续做其他的事情。

NIO 的 Selector 、 Channel 和 Buffer 的关系:
学新通

  1. 每个 channel 都会对应一个 Buffer

  2. Selector 对应一个线程, 一个线程对应多个 channel(连接)

  3. 每个 channel 都注册到 Selector选择器上

  4. Selector不断轮询查看Channel上的事件, 事件是通道Channel非常重要的概念

  5. Selector 会根据不同的事件,完成不同的处理操作

  6. Buffer 就是一个内存块 , 底层是有一个数组

  7. 数据的读取写入是通过 Buffer, 这个和 BIO , BIO 中要么是输入流,或者是输出流, 不能双向,但是 NIO 的 Buffer 是可以读也可以写 , channel 是双向的.

基于NIO服务端的代码实现:

package com.moon.server;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

/**
 * @ClassName NIOServer
 * @Author zhangqing
 * @Date 2022/8/15
 * @Description 基于NIO服务端实现
 * @Version 1.0
 */
@Slf4j
public class NIOServer {
    public NIOServer() {
        initService();
    }

    private void initService() {
        try {
            //1. 打开一个服务端通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //2. 绑定对应的端口号
            int port = 8877;
            serverSocketChannel.bind(new InetSocketAddress(port));
            //3. 通道默认是阻塞的,需要设置为非阻塞 true(默认) 为通道阻塞 false 为非阻塞
            serverSocketChannel.configureBlocking(false);
            log.info("NIO服务器启动成功,绑定端口为{}"   port);
            while (true) {
                handle(serverSocketChannel);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void handle(ServerSocketChannel serverSocketChannel) {
        // 检查是否有客户端连接 有客户端连接会返回对应的通道 , 否则返回null
        try {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel == null) {
                log.info("没有客户端连接");
                Thread.sleep(2000);
                return;
            }
            //获取客户端传递过来的数据,并把数据放在byteBuffer这个缓冲区中

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            int read = socketChannel.read(byteBuffer);
            log.info("客户端发送的消息为:{}", new String(byteBuffer.array(), 0, read));
            socketChannel.write(ByteBuffer.wrap("我是服务端".getBytes(StandardCharsets.UTF_8)));
            socketChannel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        NIOServer nioServer = new NIOServer();
    }

}

学新通

基于NIO客户端端的代码实现:

package com.moon.client;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

/**
 * @ClassName NIOClient
 * @Author zhangqing
 * @Date 2022/8/15
 * @Description Nio客户端
 * @Version 1.0
 */
@Slf4j
public class NIOClient {
    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8877));
            socketChannel.write(ByteBuffer.wrap("我是客户端 小明".getBytes(StandardCharsets.UTF_8)));
            ByteBuffer allocate = ByteBuffer.allocate(1024);
            int read = socketChannel.read(allocate);
            log.info("服务器返回的数据为{}", new String(allocate.array(),0,read, StandardCharsets.UTF_8));
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

学新通

运行效果:

service :

17:26:48.146 [main] INFO com.moon.server.NIOServer - NIO服务器启动成功,绑定端口为{}8877
17:26:48.149 [main] INFO com.moon.server.NIOServer - 没有客户端连接
17:26:50.150 [main] INFO com.moon.server.NIOServer - 没有客户端连接
17:26:52.156 [main] INFO com.moon.server.NIOServer - 客户端发送的消息为:我是客户端 小明
17:26:52.158 [main] INFO com.moon.server.NIOServer - 没有客户端连接
17:26:54.159 [main] INFO com.moon.server.NIOServer - 没有客户端连接
17:26:56.162 [main] INFO com.moon.server.NIOServer - 没有客户端连接
17:26:58.164 [main] INFO com.moon.server.NIOServer - 没有客户端连接


client :
17:26:52.160 [main] INFO com.moon.client.NIOClient - 服务器返回的数据为我是服务端

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhfeke
系列文章
更多 icon
同类精品
更多 icon
继续加载