JAVA中的IO多路复用

本文内容由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编程模型,使得开发人员可以更加方便地编写高性能的网络应用程序。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值