Java NIO通信基础示例详解

yizhihongxing

下面是“Java NIO通信基础示例详解”的完整攻略。

概述

Java NIO是Java 1.4版本引入的一种新的I/O处理方式。相较于传统的I/O方式,NIO采用了非阻塞式I/O模型,使得I/O的效率更高。本文将详细讲解Java NIO通信的基础知识和实现方式。

NIO简介

NIO是New IO的缩写,它是用来替代传统的Java IO的。Java IO(流和相关类)是面向流的,而NIO是面向缓冲区的。NIO提供了与传统IO不同的优点,例如在面向连接的传输方式中(如TCP),NIO可以通过一个单独的线程处理多个连接的输入和输出数据。

NIO的三个核心组件

1. 缓冲区 Buffer

缓冲区是一个对象,可以在其包含的数组中存储数据。Java NIO中的所有缓冲区都是 Buffer 类的子类。 Buffer 类(如下所示)有以下几个核心属性:

  • 容量(Capacity):缓冲区中最多可以存储的数据元素的数量。缓冲区的容量在创建时被固定,并且不能更改。
  • 位置(Position):下一个要读取/写入的元素索引。它默认是0,当数据被写入到缓冲区中时,位置向后移动,当从缓冲区中读取数据时,位置向前移动。
  • 限制(Limit):可以访问和操作的数据索引的下一个位置索引。默认情况下,限制等于容量。
public abstract class Buffer {
    // 容量
    private int capacity;
    // 下一个要读取/写入的元素索引
    private int position = 0;
    // 可以访问和操作的数据索引的下一个位置索引
    private int limit;
    .........
}

2. 通道 Channel

在Java NIO中, Channel是与数据源进行交互的实体。 数据源可以是文件,套接字或服务器端 另一个进程。 Channel的特点是可以被异步地读写。

常用的 Channel 类有:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

3. 选择器 Selector

Selector是Java NIO中的核心组件之一,用于处理多个 Channel的异步和非阻塞IO操作。可以注册到选择器的每个通道都可以被单个线程处理。因此,一个线程可处理多个输入和输出通道。当一个Channel需要进行读写或者连接时,可以使用选择器进行管理。因为在单个线程中,可以管理多个Channel,因此可以提高系统的运行效率。

NIO通信基础示例

示例1:实现简单的文件读写

首先,我们需要先创建一个Buffer对象将数据写入到文件中,然后读出来。

public void fileChannelDemo() throws IOException {
    String content = "hello, Java NIO";
    RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
    FileChannel channel = file.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    // 写入Buffer
    buffer.put(content.getBytes());
    // 缓存区从写模式转为读模式
    buffer.flip();
    // 将buffer中数据写入到通道
    channel.write(buffer);
    buffer.clear();
    // 将数据从通道读取到buffer中
    channel.read(buffer);
    buffer.flip();
    byte[] result = new byte[buffer.remaining()];
    buffer.get(result);
    System.out.println(new String(result));
    file.close();
}

示例2:实现客户端与服务端通信

在这个例子中,我们将实现客户端和服务端通信,客户端将向服务端发送"hello, NIO"字符串,并从服务端接收到"hello, Java NIO"字符串。

服务端部分

public class Server {
    public void server() throws IOException {
        //创建选择器
        Selector selector = Selector.open();
        //创建ServerSocketChannel对象
        ServerSocketChannel server = ServerSocketChannel.open();
        //设置通道为非阻塞状态
        server.configureBlocking(false);
        //设置监听的地址
        server.socket().bind(new InetSocketAddress(9999));
        //将通道注册在选择器上,设置监听事件为:连接(accept)
        server.register(selector, SelectionKey.OP_ACCEPT);
        //循环等待客户端连接
        while(true){
            if(selector.select(1000) == 0){
                continue;
            }
            //获取选择的键集合
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIter = keys.iterator();
            while(keyIter.hasNext()){
                SelectionKey key = keyIter.next();
                //删除已经处理的键信息
                keyIter.remove();
                //处理连接事件(当有客户端连接时)
                if(key.isAcceptable()){
                    //获取相应的ServerSocketChannel
                    ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                    //调用accept方法,接收客户端的连接
                    SocketChannel socket = serverChannel.accept();
                    //设置非阻塞状态
                    socket.configureBlocking(false);
                    //在选择器上注册相应的事件:读(read)
                    socket.register(selector, SelectionKey.OP_READ);
                } else if(key.isReadable()){//处理读事件
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int readBytes = socketChannel.read(buffer);
                    if(readBytes > 0){
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String body = new String(bytes, "UTF-8");  
                        System.out.println("Server: Receive Message -> "+ body);
                        String response = "hello, Java NIO";
                        ByteBuffer outBuffer = ByteBuffer.wrap(response.getBytes());
                        socketChannel.write(outBuffer);//将消息回送给客户端
                    }
                }
            }
        }
    }

}

客户端部分

public class Client {
        public void client() throws IOException {
            //创建SocketChannel对象
            SocketChannel socketChannel = SocketChannel.open();
            //设置通道为非阻塞状态
            socketChannel.configureBlocking(false);
            //连接服务端
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
            Selector selector = Selector.open();
            //将通道注册在选择器上,设置监听事件为:连接(connect)
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            while(true){
                if(selector.select(1000) == 0){
                    continue;
                }
                //获取选择的键集合
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> keyIter = keys.iterator();
                while(keyIter.hasNext()){
                    SelectionKey key = keyIter.next();
                    //删除已经处理的键信息
                    keyIter.remove();
                    //连接事件(由于客户端是由连接服务器开始的,因此处理连接事件在这个例子中可有可无)
                    if(key.isConnectable()){
                        SocketChannel channel = (SocketChannel) key.channel();  
                        //判断是否连接成功
                        if(channel.finishConnect()){
                            System.out.println("Client: Connect to server successful!");
                            ByteBuffer buffer = ByteBuffer.wrap("hello, NIO".getBytes());
                            buffer.flip();
                            channel.write(buffer);//向服务器发送消息
                        } else {
                            System.exit(1);
                        }
                    } else if(key.isReadable()){//处理读事件
                        SocketChannel socketChannel1 = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int readBytes = socketChannel1.read(buffer);
                        if(readBytes > 0){
                            buffer.flip();
                            byte[] bytes = new byte[buffer.remaining()];
                            buffer.get(bytes);
                            String body = new String(bytes, "UTF-8");  
                            System.out.println("Client: Receive Message -> " + body);
                        }
                    }
                }
            }
        }
}

上述实例代码实现了Java NIO的基本应用,可以尝试自己写更多的样例来加深理解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java NIO通信基础示例详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • springboot多环境配置方案(不用5分钟)

    下面是详细讲解“springboot多环境配置方案(不用5分钟)”的完整攻略: 1. 原理 Spring Boot 支持通过不同的配置文件来管理不同的环境。它提供了一个标准的命名规则:application-{profile}.properties/yml,比如 application-dev.yml,application-test.yml,applica…

    Java 2023年5月15日
    00
  • Java 从json提取数组并转换为list的操作方法

    下面是 “Java 从json提取数组并转化为list的操作方法” 的完整攻略: 1. 需要的依赖 在 Java 中使用 JSON 数据,我们需要导入相应的 JSON 解析库,这里我们以 JSON-java 为例。 在 Maven 项目中添加以下依赖即可: <dependency> <groupId>org.json</grou…

    Java 2023年5月26日
    00
  • JAVA中list,set,数组之间的转换详解

    JAVA中List、Set、数组之间的转换详解 在JAVA编程中,经常需要对不同类型的集合进行转换。常用的集合类型有List、Set、数组,它们在功能和使用方式上都有所不同。本文将详细讲解List、Set、数组之间的转换方法及示例说明,让您在实际开发中能够快速灵活地应用。 List转换成数组 将List转换成数组需要使用到List的toArray()方法,示…

    Java 2023年5月26日
    00
  • springboot 启动项目打印接口列表的实现

    Spring Boot 启动项目打印接口列表的实现 在本文中,我们将详细讲解如何使用Spring Boot实现在应用程序启动时打印接口列表。我们将介绍两种不同的方法来实现这个目标,并提供示例来说明如何使用这些方法。 方法一:使用Endpoint Spring Boot提供了Endpoint接口,它可以用于公开应用程序的一些信息。我们可以使用这个接口来实现在应…

    Java 2023年5月18日
    00
  • 基于Spring Boot的Environment源码理解实现分散配置详解

    基于Spring Boot的Environment源码理解实现分散配置详解 什么是分散配置 分散配置(Decentralized Configuration)是指将应用程序的配置从中心化的配置中心中分发到多个不同的配置文件中,并在应用程序部署时进行组合。这种方式可以提高应用程序的可维护性和灵活性。Spring Boot提供了多种实现分散配置的方式,其中Env…

    Java 2023年5月19日
    00
  • Java DatabaseMetaData用法案例详解

    Java DatabaseMetaData用法案例详解 Java DatabaseMetaData是Java JDBC API中的一个重要接口,允许您检索数据库的元数据信息,例如表和列的结构信息、索引和约束信息等。在开发Java应用程序时,您有时需要使用JDBC和DatabaseMetaData API来获取数据库的元数据信息。在本文中,我们将讨论Java …

    Java 2023年5月19日
    00
  • Jsp页面实现文件上传下载类代码第2/2页

    我会尽可能详细地讲解”Jsp页面实现文件上传下载类代码”的完整攻略。 首先,我们来讲一下文件上传的实现过程。 文件上传 HTML表单 要上传文件,我们首先需要在HTML表单中添加一个<input type=”file”>元素,例如: <form action="fileUpload.jsp" method="p…

    Java 2023年6月15日
    00
  • 一文带你学会Java网络编程

    一文带你学会Java网络编程攻略 什么是网络编程 网络编程指的是利用计算机网络实现不同计算机间的数据通信。网络编程需要使用网络协议和Socket套接字等技术。Java语言提供了丰富的网络编程API,开发者们可以利用Java语言实现各种网络通信。 Java网络编程的核心技术 协议 网络编程中最关键的技术就是各种网络协议:TCP、UDP、HTTP、SMTP、FT…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部