JAVA NIO入门

1.nio io

io主要是以流的方式处理数据

nio主要是以块的方式进行处理数据

2.nio基本概念

通道

通道channel是对原io包中流的模拟,通过它可以读写数据

与流不同的是,channel可以双向,可以读或者可以写数据

通道channel主要包括以下类型:

fileChannel:从文件中读取数据

datagramChannel:从UDP中读取数据

scoketChannel:从TCP中读写网络数据

serverScoketChannel:可以监听新进来的TCP连接,对于每个新进来的连接都会创建一个socketChannel

缓冲区

缓冲区实质上是一个数组,但是它不仅仅是一个数组,缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读写进程。

缓冲区主要包括以下:

byteBuffer

charBuffer

shortBuffer

intBuffer

longBuffer

floatBuffer

doubleBuffer

缓冲区状态变量

capacity:最大容量

position:当前已经读写字节数

limit:还可以读写字节数

文件NIO实例

 /* 获得源文件的输入字节流 */
    FileInputStream fin = new FileInputStream(src);
 
    /* 获取输入字节流的文件通道 */
    FileChannel fcin = fin.getChannel();
 
    /* 获取目标文件的输出字节流 */
    FileOutputStream fout = new FileOutputStream(dist);
 
    /* 获取输出字节流的通道 */
    FileChannel fcout = fout.getChannel();
 
    /* 为缓冲区分配 1024 个字节 */
    ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
 
    while (true) {
 
        /* 从输入通道中读取数据到缓冲区中 */
        int r = fcin.read(buffer);
 
        /* read() 返回 -1 表示 EOF */
        if (r == -1) {
            break;
        }
 
        /* 切换读写 */
        buffer.flip();
 
        /* 把缓冲区的内容写入输出文件中 */
        fcout.write(buffer);
        
        /* 清空缓冲区 */
        buffer.clear();
    }

选择器

NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。

应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义

创建选择器

Selector selector = Selector.open()

将通道注册在选择器上

ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.register(selector, SelectionKey.OP_ACCEPT);

通道必须配置为非阻塞模式

同时要需要指定具体的注册事件:

OP_CONNECT

OP_ACCPET

OP_READ

OP_WRITE


public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;

监听事件:

int num = selector.select();

获取到达的事件:

Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if (key.isAcceptable()) {
        // ...
    } else if (key.isReadable()) {
        // ...
    }
    keyIterator.remove();
}

事件循环,可直接在获取到达事件最外层套一个死循环

套接字nio实例

public static void main(String[] args) throws IOException {
 
        Selector selector = Selector.open();
 
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        ssChannel.configureBlocking(false);
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);
 
        ServerSocket serverSocket = ssChannel.socket();
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
        serverSocket.bind(address);
 
        while (true) {
 
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = keys.iterator();
 
            while (keyIterator.hasNext()) {
 
                SelectionKey key = keyIterator.next();
 
                if (key.isAcceptable()) {
 
                    ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
 
                    // 服务器会为每个新连接创建一个 SocketChannel
                    SocketChannel sChannel = ssChannel1.accept();
                    sChannel.configureBlocking(false);
 
                    // 这个新连接主要用于从客户端读取数据
                    sChannel.register(selector, SelectionKey.OP_READ);
 
                } else if (key.isReadable()) {
 
                    SocketChannel sChannel = (SocketChannel) key.channel();
                    System.out.println(readDataFromSocketChannel(sChannel));
                    sChannel.close();
                }
 
                keyIterator.remove();
            }
        }
    }
 
    private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
 
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        StringBuilder data = new StringBuilder();
 
        while (true) {
 
            buffer.clear();
            int n = sChannel.read(buffer);
            if (n == -1) {
                break;
            }
            buffer.flip();
            int limit = buffer.limit();
            char[] dst = new char[limit];
            for (int i = 0; i < limit; i++) {
                dst[i] = (char) buffer.get(i);
            }
            data.append(dst);
            buffer.clear();
        }
        return data.toString();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值