Java NIO通信基础示例详解

下面是“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日

相关文章

  • Java中字符串中连续相同字符去重方法

    在Java中,要去除字符中连续相同的字符,可以使用正则表达式或者递归的方式实现。以下是实现方法的详细攻略。 使用正则表达式 正则表达式是一种用于匹配字符串的模式,可以用来查找、替换和拆分字符串。Java中使用Pattern和Matcher两个类来进行正则表达式的匹配操作。 在去除字符串中连续相同的字符时,可以使用正则表达式来进行匹配和去重操作。具体步骤如下:…

    Java 2023年5月27日
    00
  • Go Java算法之简化路径实例详解

    Go Java算法之简化路径实例详解 本篇文章将详细讲解如何使用Go和Java算法来简化路径。首先,我们需要了解路径简化的定义和目的。 什么是路径简化? 路径简化是将路径中冗余的部分删除,使其变得更短、更干净、更易读。例如,路径”/a/b/c/../d”可以简化为”/a/b/d”。这不仅可以节省存储空间,还可以提高代码的效率。 路径简化的目的 路径简化有多种…

    Java 2023年5月19日
    00
  • JSP 开发之Spring BeanUtils组件使用

    JSP 开发之Spring BeanUtils 组件使用 Spring BeanUtils 是 Spring 框架中非常常用的一个工具类,其提供了很多方便快捷的方法用于对象属性之间的复制。本文将通过两个示例来详细讲解 Spring BeanUtils 组件的使用方法。 一、示例一:简单属性复制 下面是一个使用 Spring BeanUtils 完成简单属性复…

    Java 2023年6月15日
    00
  • 常见的排序算法,一篇就够了

    常见的排序算法 排序算法是计算机程序中常见的基本操作之一,它的作用是将一组无序的数据按照某种规则进行排序。在实际的开发中,经常需要对数据进行排序,比如搜索引擎中对搜索结果的排序、电商网站中对商品的排序等。 目前常见的排序算法有多种,下面将对一些常见的排序算法进行介绍: 1. 冒泡排序 冒泡排序是一种简单的排序算法,它重复地遍历要排序的数据,每次比较相邻的两个…

    Java 2023年5月19日
    00
  • Spring Boot2.0使用Spring Security的示例代码

    Spring Boot2.0使用Spring Security的示例代码 Spring Security是一个功能强大的安全框架,可以帮助我们实现身份验证、授权、攻击防护等功能。在Spring Boot2.0中,我们可以很方便地集成Spring Security,并实现基本的安全控制。本文将详细讲解Spring Boot2.0使用Spring Securit…

    Java 2023年5月15日
    00
  • GraalVM和Spring Native尝鲜一步步让Springboot启动飞起来66ms完成启动

    我来为你详细讲解 “GraalVM 和 Spring Native 尝鲜一步步让 Spring Boot 启动飞起来 66ms 完成启动” 的完整攻略。 什么是 GraalVM 和 Spring Native GraalVM 是一款可以运行 Java 代码的虚拟机,和其他 Java 虚拟机一样,它也可以解释字节码并执行 Java 程序。但是 GraalVM …

    Java 2023年5月19日
    00
  • java对double数组排序示例分享

    下面是“java对double数组排序示例分享”的完整攻略: 1. double数组排序的两种实现方式 在Java中对double数组进行排序通常会使用两种方式: 使用Arrays工具类的sort方法 使用DoubleStream的sorted方法 两种方式各有优缺点,下面将分别进行介绍: 1.1 利用Arrays.sort()方法 Arrays类是Java…

    Java 2023年5月26日
    00
  • Java中常用解析工具jackson及fastjson的使用

    Java中常用解析工具jackson及fastjson的使用攻略 jackson 1. 简介 jackson是一种可以将java对象转换为JSON格式,也可以将JSON格式转换为java对象的工具。它为一个高性能的JSON处理库,是Spring框架的默认JSON格式解析工具,此外也逐渐成为Java领域内最流行的JSON解析器之一。 2. 快速开始 首先我们需…

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