IO和NIO

一、IO是什么?

IO 全称:input/output 输入/输出
那么IO就是用来传输数据的!!!

那什么是流?
流,是一个抽象的东西。是一连串连续动态的数据集合

那什么是输入流?什么是输出流?

首先你要明白一件事,输入流和输出流的中心是程序!
例如: 读和写,都是以人的大脑为中心,读书是把书上的信息读进大脑,写字是把大脑里的信息写在纸上。
那么输入流就是把数据–>程序,输出流就是把程序–>目的地

向本地文件写数据用输出流,读取本地文件数据用输入流,输入输出是相对于程序来说的。

所以就有下面这个图,当你上传文件的时候,你本地就是数据源,服务器就是目的地。当你下载文件的时候,服务器就是数据源,本地就是目的地。
在这里插入图片描述

1.1 这里补充一下什么是BIO

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

那么IO就是阻塞的

这里有两个概念

什么是同步:大家都去银行取过钱对吧,每个人都是独立的,有人开车过去取钱,有人走路,每个人对于银行营业厅来说就是同步的,你们可以一起取钱嘛,互不干扰。再打个必然,你一边蹲坑一边玩手机,玩手机和蹲坑互不干扰,各干各的,没有谁规定说你蹲坑的时候一定要看抖音不能看电影吧?

什么是阻塞呢: 大家在公共厕所上过厕所吧? 尤其是火车站啊、地铁站啊,这些人多的地方。人多就算了,关键坑位还少。有很多人排队,那你想上厕所就肯定要等里面的人多来吧?这就是阻塞。

听明白没?没明白再给你们准备一张图:
有八个人排队上公共厕所,公共厕所只有四个坑位,1、2、3、4这四个人相对来说就是同步的,因为他们等的不是用一个坑位彼此互补影响,1、5 两个人就是阻塞的,因为5要等1上完了,才轮到他!!!
在这里插入图片描述

二、流的分类

方向来划分: 输入流和输出流
功能来划分: 节点流和处理流(包装流)
数据来划分: 字节流和字符流

三、NIO是什么?

NIO (new IO)

四、NIO和IO的区别

在这里插入图片描述
下面一张图看看NIO是什么,比如:你在南京想去北京玩,那么你可以做高铁去北京,高铁轨道就是通道,缓冲区就是高铁,数据就是乘客。
在这里插入图片描述
在这里插入图片描述

4.1 缓冲区(Buffer)

缓冲区(Buffer): 在Java NIO 中负责数据的存取。缓冲区就数组。用于存储不同数据类型
根据数据类型不同(Boolean 除外),提供相应类型的缓冲区:

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FoaltBuffer
  • DoubleBuffer

上述缓冲区的管理方式几乎一致,通过 allocate() 获取缓冲区

缓冲区获取数据的两个核心的方法:

  • put(): 存入数据到缓冲区
  • get(): 从缓冲区获取数据

缓冲区中的四个核心的属性:

  • capacity: 容量, 表示缓冲区中最大存储的容量。一旦声明,不可改变。
  • limit: 界限, 表示缓冲区中可以操作数据的大小。(limit 后面的数据不能进行读写)
  • position: 位置, 表示缓冲区中正在操作数据的位置。
  • mark: 标记, 表示记录当前position的位置。可以通过 reset() 恢复到 mark 的位置。

0 <= mark <= position <= limit <= capacity

代码部分:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;


import java.nio.ByteBuffer;

/**
 *
 * 一、缓冲区(Buffer): 在Java NIO 中负责数据的存取。缓冲区就数组。用于存储不同数据类型
 *
 *根据数据类型不同(Boolean 除外),提供相应类型的缓冲区:
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * FoaltBuffer
 * DoubleBuffer
 *
 * 上述缓冲区的管理方式几乎一致,通过  allocate()  获取缓冲区
 *
 * 二、缓冲区获取数据的两个核心的方法:
 * put(): 存入数据到缓冲区
 * get(): 从缓冲区获取数据
 *
 * 三、缓冲区中的四个核心的属性:
 * capacity: 容量, 表示缓冲区中最大存储的容量。一旦声明,不可改变。
 * limit: 界限, 表示缓冲区中可以操作数据的大小。(limit 后面的数据不能进行读写)
 * position: 位置, 表示缓冲区中正在操作数据的位置。
 * mark: 标记, 表示记录当前position的位置。可以通过 reset() 恢复到 mark 的位置。
 *
 * 0 <= mark <= position <= limit <= capacity
 *
 * @author yangjikang
 * @date 2019/7/9 16:30
 * @modified By yangjikang
 */
public class demo01 {
    public static void main(String[] args) {

        String s = "abcdef";
        //1.分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(10);
        System.out.println("==================allocate====================");
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        //2.利用put()存入数据到缓冲区
        buf.put(s.getBytes());
        System.out.println("==================put()====================");
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        //3.切换读取数据模式
        buf.flip();
        System.out.println("==================flip()====================");
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        //4.利用get()方法读取缓冲区中的数据
        byte[] temp = new byte[buf.limit()];
        buf.get(temp);
        System.out.println("==================get()====================");
        System.out.println(new String(temp,0,temp.length));
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        //5.rewind() : 可重复读
        buf.rewind();
        System.out.println("==================rewind()====================");
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        //6.clear() : 清空缓冲区,但是缓冲区里的数据还存在,只是处于“被遗忘”状态
        buf.clear();
        System.out.println("==================clear()====================");
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());

        System.out.println((char) buf.get());

    }
}

控制台:
在这里插入图片描述
在这里插入图片描述
flip()反转,将指针重置回开始。

mark 和 reset
代码部分:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.nio.ByteBuffer;

/**
 * mark: 标记, 表示记录当前position的位置。可以通过 reset() 恢复到 mark 的位置。
 *
 * @author yangjikang
 * @date 2019/7/10 9:58
 * @modified By yangjikang
 */
public class demo02 {
    public static void main(String[] args) {
        String str = "1234567";
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(str.getBytes());

        buffer.flip();

        //创建临时接收缓冲区数据的数组
        byte[] temp = new byte[buffer.limit()];
        //读取三个字符到temp从0号下标开始放
        buffer.get(temp, 0, 3);
        System.out.println("第一次读取内容: " + new String(temp, 0, temp.length));

        System.out.println("第一次读取后的position位置: " + buffer.position());
        //标记当前position位置
        buffer.mark();

        //读取两个字符到temp从1号下标开始放
        buffer.get(temp, 1, 2);
        System.out.println("第二次读取内容: " + new String(temp, 0, temp.length));

        System.out.println("第二次读取后的position位置: " + buffer.position());

        //通过reset恢复到mark位置
        buffer.reset();
        System.out.println("通过reset恢复后的position位置: " + buffer.position());
    }
}

控制台:
在这里插入图片描述

五、NIO的直接缓冲区和非直接缓冲区

非直接缓冲区: 通过allocate() 方法分配缓冲区,将缓冲区建立在JVM内存上。
直接缓冲区: 通过allocateDirect() 方法分配直接内存,将缓冲区建立在物理内存中。

看图
在这里插入图片描述
在这里插入图片描述
代码:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 一、通道(Channel): 用于源节点和目标节点的连接。在Java NIO中负责缓冲区中数据的传输。Channel本身不存储数据,
 * 需要配合缓冲区(Buffer)进行数据的传输
 * <p>
 * 二、通道的主要是实现类
 * java.nio.channels.channel 接口:
 * |--FileChannel
 * |--SocketChannel
 * |--ServerSocketChannel
 * |--DatagramChannel
 * <p>
 * 三、获取通道
 * 1.Java 针对支持通道的类提供了 getChannel()方法
 * 本地IO:
 * FileInputStream/FileOutputStream
 * RandomAccessFile
 * <p>
 * 网络IO:
 * Socket
 * ServerSocket
 * Datagram
 * <p>
 * 2.在JDK1.7中的NIO.2针对各个通道提供了静态方法open()
 * 3.在JDK1.7中的NIO.2的Files 工具类 newByteChannel()
 *
 * @author yangjikang
 * @date 2019/7/10 13:47
 * @modified By yangjikang
 */
public class demo03 {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        int count = 0;
        try {
            fileInputStream = new FileInputStream("1.jpg");
            fileOutputStream = new FileOutputStream("2.jpg");

            //step.1 获取通道
            inChannel = fileInputStream.getChannel();
            outChannel = fileOutputStream.getChannel();

            //step.2 分配指定大小的缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            //step.3 将通道中数据放入缓冲区中
            while (inChannel.read(byteBuffer) != -1) {
                byteBuffer.flip();//切换读模式

                //step.4 将缓冲区中的数据读入通道中
                outChannel.write(byteBuffer);
                byteBuffer.clear();//清空当前缓冲区
                count++;
            }
            System.out.println(count);
            System.out.println(inChannel);
            System.out.println(outChannel);
            System.out.println(fileInputStream);
            System.out.println(fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            inChannel.close();
            outChannel.close();
            fileInputStream.close();
            fileOutputStream.close();
        }

    }
}

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @author yangjikang
 * @date 2019/7/10 14:16
 * @modified By yangjikang
 */
public class demo04 {
    public static void main(String[] args) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            //使用直接缓冲区完成文件的复制(内存映射文件)
            inputChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
            outputChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

            //内存映射文件
            MappedByteBuffer inputMap = inputChannel.map(FileChannel.MapMode.READ_ONLY, 0, inputChannel.size());
            MappedByteBuffer outputMap = outputChannel.map(FileChannel.MapMode.READ_WRITE, 0, inputChannel.size());

            //直接对缓冲区进行数据的读写操作
            byte[] bytes = new byte[inputMap.limit()];
            inputMap.get(bytes);
            outputMap.put(bytes);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            inputChannel.close();
            outputChannel.close();
        }
    }
}

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 *
 * 四、通道直接的数据传输
 * transferTo()
 * transferFrom()
 *
 * @author yangjikang
 * @date 2019/7/10 14:37
 * @modified By yangjikang
 */
public class demo05 {
    public static void main(String[] args) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            //使用直接缓冲区完成文件的复制(内存映射文件)
            inputChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
            outputChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

//            inputChannel.transferTo(0, inputChannel.size(), outputChannel);
            outputChannel.transferFrom(inputChannel,0,inputChannel.size());

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            inputChannel.close();
            outputChannel.close();
        }
    }
}

六、分散读取和聚集写入

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 五、分散(Scatter)和聚集(Gather)
 * 分散读取(Scattering Reads): 将通道中的数据分散到多个缓冲区中
 * 聚集写入(Gathering Writes): 将多个缓冲区中的数据聚集到通道中
 *
 * @author yangjikang
 * @date 2019/7/10 14:53
 * @modified By yangjikang
 */
public class demo06 {
    public static void main(String[] args) throws IOException {
        RandomAccessFile read = new RandomAccessFile("1.txt", "rw");

        //step.1 获取通道
        FileChannel channel = read.getChannel();

        //step.2 分配指定大小的缓冲区
        ByteBuffer allocate1 = ByteBuffer.allocate(50);
        ByteBuffer allocate2 = ByteBuffer.allocate(100);

        //step.3 分散读取数据到多个缓冲区
        ByteBuffer[] byteBuffers = {allocate1, allocate2};
        channel.read(byteBuffers);
        for (ByteBuffer byteBuffer : byteBuffers) {
            byteBuffer.flip();
        }

        //step.4 打印结果
        System.out.println(new String(byteBuffers[0].array(), 0, byteBuffers[0].limit()));
        System.out.println("========================================");
        System.out.println(new String(byteBuffers[1].array(), 0, byteBuffers[1].limit()));

        //聚集写入
        RandomAccessFile write = new RandomAccessFile("3.txt", "rw");
        FileChannel writeChannel = write.getChannel();
        writeChannel.write(byteBuffers);
    }
}

七、字符集

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

/**
 * 六、字符集:Charset
 * 编码:字符串 --> 字节数组
 * 解码:字节数组 --> 字符串
 *
 * @author yangjikang
 * @date 2019/7/10 15:57
 * @modified By yangjikang
 */
public class demo07 {
    public static void main(String[] args) throws CharacterCodingException {
        //查看字符集有哪些
        SortedMap<String, Charset> stringCharsetSortedMap = Charset.availableCharsets();
        Set<Map.Entry<String, Charset>> entries = stringCharsetSortedMap.entrySet();
        for (Map.Entry<String, Charset> entry : entries) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
        //指定编码方式
        Charset gbk = Charset.forName("GBK");

        //获取编码器
        CharsetEncoder charsetEncoder = gbk.newEncoder();
        //获取解码器
        CharsetDecoder charsetDecoder = gbk.newDecoder();

        //创建字符缓冲区
        CharBuffer allocate = CharBuffer.allocate(1024);
        allocate.put("yangjikang");
        allocate.flip();

        //编码
        ByteBuffer encode = charsetEncoder.encode(allocate);
        for (int i = 0; i < encode.limit(); i++) {
            System.out.println(encode.get());
        }

        //解码
        encode.flip();
        CharBuffer decode = charsetDecoder.decode(encode);
        System.out.println(decode);
    }
}

八、IO阻塞和NIO非阻塞

read(缓冲区) --> 上车 :可以理解为把 数据源 通道(channel)里面的数据读取到缓冲区(buffer)
write(缓冲区) --> 下车 :可以理解为把缓冲区(buffer)里面的数据读取到 目的地 通道(channel)
在这里插入图片描述
在这里插入图片描述

8.1阻塞网络通信

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import org.junit.Test;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * 阻塞和非阻塞
 *
 * 一、使用NIO完成网路通信的三个核心:
 * 1.通道:负责连接
 *  java.nio.channels.channel 接口:
 *  |-- SelectableChannel
 *      |-- SocketChannel
 *      |-- ServerSocketChannel
 *      |-- DatagramChannel
 *
 *      |-- Pipe.SinkChannel
 *      |-- Pipe.SourceChannel
 *
 * 2.缓冲区:负责数据存储
 *
 * 3.选择器: 是 SelectableChannel的多路复用器。用于监听SelectableChannel的IO状况。
 *
 * @author yangjikang
 * @date 2019/7/10 16:36
 * @modified By yangjikang
 */
public class demo08 {

    @Test
    public void Client() throws IOException {
        //获取通道
        SocketChannel open = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989));

        RandomAccessFile read = new RandomAccessFile("1.jpg", "rw");
        FileChannel channel = read.getChannel();

        //分配指定大小的缓冲区
        ByteBuffer allocate = ByteBuffer.allocate(1024);

        //读取本地文件,并发送到服务器
        while(channel.read(allocate) != -1){
            allocate.flip();
            open.write(allocate);
            allocate.clear();
        }
        read.close();
        open.close();

    }
    @Test
    public void Server() throws IOException {
        //获取通道
        ServerSocketChannel open = ServerSocketChannel.open();

        RandomAccessFile read = new RandomAccessFile("15.jpg", "rw");
        FileChannel channel = read.getChannel();

        //绑定连接
        open.bind(new InetSocketAddress(8989));

        //获取客服端连接的通道
        SocketChannel accept = open.accept();

        //分配一个指定大小的缓冲区
        ByteBuffer allocate = ByteBuffer.allocate(1024);

        //接受客服端的数据保存到本地
        while(accept.read(allocate) != -1){
            allocate.flip();
            channel.write(allocate);
            allocate.clear();
        }

        //关闭通道
        channel.close();
        open.close();
    }
}

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import org.junit.Test;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;

/**
 * 阻塞NIO
 *
 * @author yangjikang
 * @date 2019/7/10 17:56
 * @modified By yangjikang
 */
public class demo09 {
    @Test
    public void Client() throws IOException, InterruptedException {
        //获取通道
        SocketChannel open = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989));

        RandomAccessFile read = new RandomAccessFile("1.jpg", "rw");
        FileChannel channel = read.getChannel();

        //分配指定大小的缓冲区
        ByteBuffer allocate = ByteBuffer.allocate(1024);

        //读取本地文件,并发送到服务器
        while (channel.read(allocate) != -1) {
            allocate.flip();
            open.write(allocate);
            allocate.clear();
        }
        open.shutdownOutput();
        //接收服务端的反馈
        int len;
        while ((len = open.read(allocate)) != -1) {
            System.out.println("接收服务端反馈");
            allocate.flip();
            System.out.println(new String(allocate.array(), 0, len));
            allocate.clear();
        }
        read.close();
        open.close();

    }

    @Test
    public void Server() throws IOException {
        //获取通道
        ServerSocketChannel open = ServerSocketChannel.open();

        RandomAccessFile read = new RandomAccessFile("18.jpg", "rw");
        FileChannel channel = read.getChannel();

        //绑定连接
        open.bind(new InetSocketAddress(8989));

        //获取客服端连接的通道
        SocketChannel accept = open.accept();

        //分配一个指定大小的缓冲区
        ByteBuffer allocate = ByteBuffer.allocate(1024);

        //接受客服端的数据保存到本地
        while (accept.read(allocate) != -1) {
            allocate.flip();
            channel.write(allocate);
            allocate.clear();
        }
        allocate.put("服务端接收数据成功!".getBytes());
        allocate.flip();
        accept.write(allocate);
        accept.shutdownOutput();
        //关闭通道
        channel.close();
        accept.close();
        open.close();
    }
}

8.2非阻塞网络通信

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.util.Iterator;

/**
 * 阻塞和非阻塞
 *
 * 一、使用NIO完成网路通信的三个核心:
 * 1.通道:负责连接
 *  java.nio.channels.channel 接口:
 *  |-- SelectableChannel
 *      |-- SocketChannel
 *      |-- ServerSocketChannel
 *      |-- DatagramChannel
 *
 *      |-- Pipe.SinkChannel
 *      |-- Pipe.SourceChannel
 *
 * 2.缓冲区:负责数据存储
 *
 * 3.选择器: 是 SelectableChannel的多路复用器。用于监听SelectableChannel的IO状况。
 *
 * @author yangjikang
 * @date 2019/7/10 16:36
 * @modified By yangjikang
 */
public class demo10 {

    //客户端
    @Test
    public void client() throws IOException {
        //获取通道
        SocketChannel open = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8899));

        //切换成非阻塞模式
        open.configureBlocking(false);

        //分配指定大小的缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //发送数据给服务端
        byteBuffer.put("来自客户端的一条数据".getBytes());
        byteBuffer.flip();
        open.write(byteBuffer);
        byteBuffer.clear();

        //关闭通道
        open.close();
    }

    //服务端
    @Test
    public void server() throws IOException {
        //获取通道
        ServerSocketChannel open = ServerSocketChannel.open();

        //切换非阻塞模式
        open.configureBlocking(false);

        //绑定连接
        open.bind(new InetSocketAddress(8899));

        //获取选择器
        Selector selector = Selector.open();

        //将通道注册到选择器上,并且指定”监听接收事件“
        open.register(selector, SelectionKey.OP_ACCEPT);

        //轮询获取选择器上已经准备就绪的事件
        while (selector.select() > 0){
            //获取当前选择器所有已经准备就绪的事件key
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while (iterator.hasNext()){
                //获取准备就绪的事件
                SelectionKey next = iterator.next();

                //判断具体是什么事件
                if(next.isAcceptable()){//接收事件
                    //获取客户端连接
                    SocketChannel acceptChannel = open.accept();

                    //切换非阻塞模式
                    acceptChannel.configureBlocking(false);

                    //将通道注册到选择器上
                    acceptChannel.register(selector,SelectionKey.OP_READ);
                }else if(next.isReadable()){//读取事件
                    //获取选择器上”读就绪“状态的通道
                    SocketChannel readChannel = (SocketChannel)next.channel();

                    //读取数据
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //创建一个指定大小的缓冲器

                    while (readChannel.read(byteBuffer) != -1 ){
                        byteBuffer.flip();
                        System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
                        byteBuffer.clear();
                    }
                }
                //取消选择键(SelectionKey)
                iterator.remove();
            }


        }
    }
}

8.3非阻塞数据包(DatagramChannel)通道

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;

/**
 * @author yangjikang
 * @date 2019/7/11 11:43
 * @modified By yangjikang
 */
public class demo11 {

    @Test
    public void send() throws IOException {
        DatagramChannel dc = DatagramChannel.open();

        dc.configureBlocking(false);

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        byteBuffer.put(("来自send的数据:你好").getBytes());
        byteBuffer.flip();
        dc.send(byteBuffer, new InetSocketAddress("127.0.0.1", 8899));
        byteBuffer.clear();
        dc.close();
    }

    @Test
    public void receive() throws IOException {

        DatagramChannel dc = DatagramChannel.open();

        dc.configureBlocking(false);

        dc.bind(new InetSocketAddress(8899));

        Selector selector = Selector.open();

        dc.register(selector, SelectionKey.OP_READ);

        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                if (next.isReadable()) {
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    dc.receive(byteBuffer);

                    byteBuffer.flip();

                    System.out.println(new String(byteBuffer.array(), 0, byteBuffer.limit()));

                    byteBuffer.clear();
                }
            }
            iterator.remove();
        }
    }
}

8.4 单向管道(Pipe)

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */
package nio;

import org.junit.Test;

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

/**
 * 3
 *
 * @author yangjikang
 * @date 2019/7/11 11:58
 * @modified By yangjikang
 */
public class demo12 {

    @Test
    public void pipe() throws IOException {
        //获取管道
        Pipe pipe = Pipe.open();

        //将缓冲区的数据写入管道
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        Pipe.SinkChannel sink = pipe.sink();
        byteBuffer.put("向单向管道发送数据".getBytes());
        byteBuffer.flip();
        sink.write(byteBuffer);

        //读取缓冲区里面的数据
        Pipe.SourceChannel source = pipe.source();

        //创建一个缓冲区用来接收数据
        ByteBuffer accpetByteBuffer = ByteBuffer.allocate(1024);

        byteBuffer.flip();
        source.read(accpetByteBuffer);

        System.out.println(new String(accpetByteBuffer.array(),0,accpetByteBuffer.limit()));
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值