Java NIO 网络编程模型讲解和实战demo

Java NIO(New IO)是Java 1.4引入的一组用于替代Java IO的API,其最大的特点就是支持非阻塞IO。Java NIO的非阻塞IO是基于选择器(Selector)和通道(Channel)实现的,与传统的Java IO API不同,它可以同时处理多个连接,而且这些连接不会阻塞线程。在Java NIO中,一个线程可以处理多个通道(连接),因此可以实现高并发。

Java NIO的网络编程模型有以下几个组成部分:

1、Channel:通道是Java NIO中一个基础的概念,它相当于Java IO中的Stream,但是它可以同时进行读写操作,而且可以进行非阻塞读写操作。

2、Buffer:缓冲区是一个容器,用来存储数据。Java NIO中所有数据都是用Buffer来处理的,Buffer实现了Java NIO中的非阻塞IO。

3、Selector:选择器是Java NIO中的另一个重要概念,它可以监视多个通道的IO状况,当某个通道的数据准备好了读写时,它就可以通知程序来进行处理。

Java NIO的网络编程模型基于事件驱动,当一个通道中有数据可读写时,Selector会通知程序进行处理。在处理数据时,程序需要从通道中读取数据到Buffer中,然后再从Buffer中处理数据。

下面是一个简单的Java NIO网络编程模型的示例代码,其中包含了Channel、Buffer和Selector的使用:

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.SocketChannel;
import java.util.Iterator;

public class NioClient {

    public static void main(String[] args) {
        try {
            // 创建SocketChannel并连接到远程服务器
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("localhost", 8888));

            // 创建Selector并将SocketChannel注册到Selector上
            Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);

            while (true) {
                // 阻塞等待就绪的事件,每隔1秒钟唤醒一次
                if (selector.select(1000) == 0) {
                    continue;
                }

                // 处理就绪的事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if (key.isConnectable()) {
                        // 连接就绪,完成连接操作
                        SocketChannel channel = (SocketChannel) key.channel();
                        if (channel.isConnectionPending()) {
                            channel.finishConnect();
                        }
                        channel.configureBlocking(false);
                        channel.write(ByteBuffer.wrap("Hello, server".getBytes()));
                        channel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        // 可读就绪,读取数据并处理
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int len = channel.read(buffer);
                        if (len > 0) {
                            buffer.flip();
                            byte[] bytes = new byte[buffer.remaining()];
                            buffer.get(bytes);
                            System.out.println("Received from server: " + new String(bytes));
                        } else if (len < 0) {
                            channel.close();
                            key.cancel();
                        }
                    }
                    iterator.remove();
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

该示例代码实现了一个NIO客户端,其中:

1、创建一个SocketChannel并连接到远程服务器;
2、创建一个Selector并将SocketChannel注册到Selector上;
3、在循环中阻塞等待就绪的事件,每隔1秒钟唤醒一次;
4、处理就绪的事件:
1)如果是连接就绪事件,完成连接操作并将SocketChannel注册到Selector上,以便后续处理可读就绪事件;
2)如果是可读就绪事件,读取数据并处理。