NIO的实战教程(简单且高效)

1. 参考

建议按顺序阅读以下三篇文章
为什么NIO被称为同步非阻塞?
Java IO 与 NIO:高效的输入输出操作探究
【Java.NIO】Selector,及SelectionKey

2. 实战

我们将模拟一个简单的HTTP服务器,它将响应客户端请求并返回一个固定的响应("Hello, World!")。我们将使用IO和NIO两种不同的方式实现此服务器。
2.1 传统阻塞IO

java 复制代码
import java.io.*;
public class TraditionalIOExample {
    public static void main(String[] args) {
        try {
            // 打开文件
            InputStream input = new FileInputStream("example.txt");
            OutputStream output = new FileOutputStream("output.txt");

            // 读取和写入数据
            int data;
            while ((data = input.read()) != -1) {
                output.write(data);
            }

            // 关闭文件
            input.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 非阻塞NIO

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioHttpServer {
    public static void main(String[] args) {
        try {
        	// 创建服务端通道
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            // 绑定访问端口
            serverChannel.socket().bind(new InetSocketAddress(8080));
            // 通道设置为非阻塞
            serverChannel.configureBlocking(false);

			// 通过open方法创建一个Selector
            Selector selector = Selector.open();
            /** 
            必须将channel注册到selector上,并订阅OP_ACCEPT事件
             		SelectionKey.OP_CONNECT  channel成功连接到另一个服务器称为"连接就绪"
					SelectionKey.OP_ACCEPT	 server socket channel准备好接收新进入的连接称为"接收就绪"
					SelectionKey.OP_READ	 有数据可读的通道可以说是"读就绪"
					SelectionKey.OP_WRITE	 有数据可写的通道可以说是"读就绪"
			*/
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
            	// 返回你所感兴趣的事件(连接,接受,读或写)已经准备就绪的那些通道
                int readyChannels = selector.select();
                if (readyChannels == 0){
                	continue;
                }
                // 访问"已选择键集"中的就绪通道
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                
                // 可以遍历这个已选择的集合来访问就绪的通道
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    // 注意每次迭代末尾的remove()调用,Selector不会自己从已选择集中移除SelectioKey实例,必须在处理完通道时自己移除。
                    keyIterator.remove();

					// 一个server socket channel准备号接收新进入的连接称为"接收就绪"
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        // 客户端socker注册进来
                        SocketChannel clientChannel = server.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                        // 客户端通道是否有数据流进来
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        clientChannel.read(buffer);
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String request = new String(bytes);

                        String response = "HTTP/1.1 200 OK\r\n\r\nHello, World!\r\n";
                        ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                        clientChannel.write(responseBuffer);
                        clientChannel.close();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 模型

上述代码结合该模型,第二次阅读代码,会有更深的理解

4. 原理

多路复用才是NIO不阻塞的原因

相关推荐
郑州光合科技余经理34 分钟前
PHP构建:支撑欧美澳市场的同城生活服务平台开发
java·开发语言·数据库·uni-app·php·排序算法·生活
超级大只老咪8 小时前
数组相邻元素比较的循环条件(Java竞赛考点)
java
小浣熊熊熊熊熊熊熊丶8 小时前
《Effective Java》第25条:限制源文件为单个顶级类
java·开发语言·effective java
毕设源码-钟学长8 小时前
【开题答辩全过程】以 公交管理系统为例,包含答辩的问题和答案
java·eclipse
啃火龙果的兔子8 小时前
JDK 安装配置
java·开发语言
星哥说事8 小时前
应用程序监控:Java 与 Web 应用的实践
java·开发语言
派大鑫wink8 小时前
【JAVA学习日志】SpringBoot 参数配置:从基础到实战,解锁灵活配置新姿势
java·spring boot·后端
xUxIAOrUIII9 小时前
【Spring Boot】控制器Controller方法
java·spring boot·后端
Dolphin_Home9 小时前
从理论到实战:图结构在仓库关联业务中的落地(小白→中级,附完整代码)
java·spring boot·后端·spring cloud·database·广度优先·图搜索算法
醇氧9 小时前
org.jetbrains.annotations的@Nullable 学习
java·开发语言·学习·intellij-idea