Java中的NIO使用小结

NIO中主要包含以下3大对象

  • Buffer
  • Channel
  • Selector

NIO的核心原理如下图所示

缓冲区Buffer

常用方法

名称说明
flip()切换为读模式,limit设置为position位置,position设置为0
get()读取一个字节
get(int index)读取指定索引的字节
get(byte[] dest)读取多个字节
rewind()将position设置为0,可以重复读取
clear()切换为写模式,position设置为0,limit设置为capacity
array()把缓冲区转成字节数组

通道Channel

1.通道可读可写,而流一般是单向的(所以有InputStream, OutputStream)
2.通道可以异步读写
3.通道总是基于Buffer来读写

Channel相关的常用类

  • FileChannel
  • DatagramChannel
  • ServerSocketChannel
  • SocketChannel

FileChannel用于文件的数据读写,DatagramChannel用于UDP的数据读写,ServerSocketChannel和SocketChannel主要用于TCP的数据读写(类似于ServerSocket和Socket)。

代码示例如下:

NIOServerDemo.java

public class NIOServerDemo {

    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(9999));
        serverSocketChannel.configureBlocking(false);
        System.out.println("server is started...");

        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if(socketChannel==null){
                System.out.println("no client, do other things...");
                Thread.sleep(2000);
                continue;
            }

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            int read = socketChannel.read(byteBuffer); // read为正:读到的有效字节数; read=0: 没有读到数据; read=-1:读到末尾
            String message = new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8);
            System.out.println("client msg: "+message);

            socketChannel.write(ByteBuffer.wrap("hello client".getBytes(StandardCharsets.UTF_8)));
            socketChannel.close();
        }
    }
}

NIOClientDemo.java

public class NIOClientDemo {
    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
        socketChannel.write(ByteBuffer.wrap("hi server".getBytes(StandardCharsets.UTF_8)));

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        int read = socketChannel.read(byteBuffer);
        String message = new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8);
        System.out.println("server msg:"+message);

        socketChannel.close();
    }
}

选择器Selector

selector基本介绍

常用API

selector.open() 返回一个选择器对象

selector.select() 阻塞

selector.select(1000) 阻塞1000毫秒

selector.selectedKeys() 返回selectedKey集合

SelectionKey.isAcceptable() 是否是连接继续事件

SelectionKey.isConnectable() 是否是连接就绪事件

SelectionKey.isReadable() 是否是读就绪事件

SelectionKey.isWritable() 是否是写就绪事件

SelectionKey中定义的4种事件

SelectionKey.OP_ACCEPT 接收连接继续事件

SelectionKey.OP_CONNECT 连接就绪事件

SelectionKey.OP_READ 读就绪事件

SelectionKey.OP_WRITE 写就绪事件

selector编码

基于Selector的使用示例如下:

NIOSelectorServerDemo.java

public class NIOSelectorServerDemo {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(9999));
        serverSocketChannel.configureBlocking(false);
        
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("server started...");
        while (true) {
            int select = selector.select(2000);
            if (select == 0) {
                System.out.println("no event...");
                continue;
            }

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                if (selectionKey.isAcceptable()) {
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("client try to connect...");
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }

                if (selectionKey.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int read = socketChannel.read(byteBuffer);
                    if (read > 0) {
                        System.out.println("msg from client:" + new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8));

                        //write msg to client
                        socketChannel.write(ByteBuffer.wrap("hello client".getBytes(StandardCharsets.UTF_8)));
                        socketChannel.close();
                    }
                }
                iterator.remove();
            }
        }
    }
}

NIOSelectorClientDemo.java

public class NIOSelectorClientDemo {
    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
        socketChannel.write(ByteBuffer.wrap("hi server".getBytes(StandardCharsets.UTF_8)));

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        int read = socketChannel.read(byteBuffer);
        String message = new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8);
        System.out.println("server msg:"+message);

        socketChannel.close();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值