本文内容由AI生成。
以下是一个基于Java NIO的简单IO多路复用示例:
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.util.Iterator;
public class NIOServer {
private static final int BUF_SIZE = 1024;
private static final int PORT = 8080;
private static final int TIMEOUT = 3000;
public static void main(String[] args) {
selector();
}
public static void selector() {
Selector selector = null;
ServerSocketChannel ssc = null;
try {
selector = Selector.open();
ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(PORT));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select(TIMEOUT) == 0) {
System.out.print(".");
continue;
}
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
handleAccept(key);
}
if (key.isReadable()) {
handleRead(key);
}
if (key.isValid() && key.isWritable()) {
handleWrite(key);
}
if (key.isValid() && key.isConnectable()) {
System.out.println("isConnectable = true");
}
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (selector != null) {
selector.close();
}
if (ssc != null) {
ssc.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void handleAccept(SelectionKey key) throws IOException {
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
SocketChannel sc = ssChannel.accept();
sc.configureBlocking(false);
sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE));
}
public static void handleRead(SelectionKey key) throws IOException {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buf = (ByteBuffer) key.attachment();
long bytesRead = sc.read(buf);
while (bytesRead > 0) {
buf.flip();
while (buf.hasRemaining()) {
System.out.print((char) buf.get());
}
System.out.println();
buf.clear();
bytesRead = sc.read(buf);
}
if (bytesRead == -1) {
sc.close();
}
}
public static void handleWrite(SelectionKey key) throws IOException {
ByteBuffer buf = (ByteBuffer) key.attachment();
buf.flip();
SocketChannel sc = (SocketChannel) key.channel();
while (buf.hasRemaining()) {
sc.write(buf);
}
buf.compact();
}
}
此示例使用Java NIO实现了一个简单的IO多路复用的服务器程序,用于处理客户端的连接、读取和写入请求。其中,Selector是Java NIO中的关键组件,通过它可以同时监视多个Channel的状态,根据不同状态来执行相应的操作。
在程序启动时,首先创建一个Selector对象,并将ServerSocketChannel注册到Selector中,以便可以接收客户端的连接请求。然后,程序进入主循环,不断轮询Selector的状态,如果有Channel的状态发生了变化,则根据不同的状态来执行相应的操作。
如果有新的客户端连接请求,则调用handleAccept()方法来处理。在handleAccept()方法中,首先获取到ServerSocketChannel,然后调用accept()方法来接收客户端的连接请求,并将接收到的SocketChannel注册到Selector中,以便可以读取客户端发送的数据。
如果有客户端发送数据,则调用handleRead()方法来处理。在handleRead()方法中,首先获取到SocketChannel,并获取到之前注册的ByteBuffer,然后调用read()方法来读取客户端发送的数据,并将读取到的数据输出到控制台。
如果需要向客户端发送数据,则调用handleWrite()方法来处理。在handleWrite()方法中,首先获取到ByteBuffer,然后将它的状态切换为写模式,以便可以向其中写入数据。接着,获取到SocketChannel,并调用write()方法将数据写入到SocketChannel中。最后,将ByteBuffer的状态切换为读模式,以便可以继续读取数据。
在主循环中,通过调用Selector的select()方法来等待Channel的状态发生变化,如果有Channel的状态发生变化,则select()方法会返回可用的Channel数量,并使用selectedKeys()方法获取可用的SelectionKey集合。然后,遍历SelectionKey集合,根据不同的状态来执行相应的操作。
在示例中,我们使用了四种状态:OP_ACCEPT、OP_READ、OP_WRITE和OP_CONNECT。这些状态可用于监视Channel的连接、读取、写入和连接建立状态。
最后,在程序结束时,需要释放资源,关闭Selector和ServerSocketChannel。这可以通过try-with-resources或在finally块中手动关闭实现。
总之,IO多路复用是一种优化网络编程性能的重要技术。Java NIO提供了Selector、Channel和Buffer等组件,可以方便地实现IO多路复用。通过使用Java NIO,可以实现高效的网络编程,并且可以处理大量的客户端连接,提高系统的并发处理能力。
在Java NIO中,Selector是一个可选择的通道管理器,用于监视多个通道是否有事件发生。通道可以注册到Selector中,然后Selector负责监视这些通道的状态,并在这些通道有事件发生时通知应用程序。通道和Selector的注册、注销和事件通知都是异步的,因此可以实现非阻塞式的IO操作。
在Java NIO中,与传统IO模型不同的是,每个通道都有一个关联的Buffer,可以直接将数据读取到或写入到这个Buffer中,而不必像传统IO模型那样先创建一个byte数组,然后将数据读取到byte数组中或从byte数组中写入数据。
另外,在Java NIO中,通道和Buffer都是双向的,可以同时支持读和写操作,因此可以在读取完数据后立即写入数据,而无需等待写操作完成即可开始读取数据。
综上所述,Java NIO提供了一种高效、灵活、可扩展的IO编程模型,使得开发人员可以更加方便地编写高性能的网络应用程序。