栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java NIO 模型代码示例

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java NIO 模型代码示例

在高并发(持续大量的连接同时请求)场景中,之前的两种 BIO 优化方案都需要消耗大量的线程来维持连接。并且 CPU 在线程切换上消耗很大。

Java NIO 模型的主要优势:少量的线程就可以处理大量连接的请求。

主要组成:

  1. Channel 通道:IO 传输发生时数据通过的入口
  2. Buffer 缓冲区:可以理解为数据在管道传输时的起点和终点
  3. Selector 选取器(IO监听器):负责监听 IO 事件

所用通道都向 Selector 注册,Selector 负责轮询检测,然后服务端进程会阻塞在 Selector 的 select() 方法,直到注册的通道有事件就绪。

代码示例 : NIOServer.java

package org.io.nio;

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

public class NIOServer {

    // 服务端通道
    private ServerSocketChannel serverChannel;

    // 选择器
    private Selector selector;

    // 默认服务绑定端口
    private static int DEFAULT_BIND_PORT = 9000;

    public NIOServer(int port) {
        initServer(port);
    }

    private void initServer(int port) {
        try {
            // 开启一个服务通道
            this.serverChannel = ServerSocketChannel.open();
            // 将通道绑定到指定端口
            this.serverChannel.bind( (port < 1 || port > 65535) ?
                    new InetSocketAddress(DEFAULT_BIND_PORT) :
                    new InetSocketAddress(port));
            // 将通道设置为非阻塞模式
            this.serverChannel.configureBlocking(false);
            // 打开一个 IO 监视器:Selector
            this.selector = Selector.open();
            // 将服务通道注册到 Selector 上,并在服务端通道注册 OP_ACCEPT 事件
            this.serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        } catch (IOException ioException) {
            ioException.printStackTrace();
            System.out.println("init exception: " + ioException);
        }
    }

    public void startServer() throws InterruptedException {
        while (true){
            System.out.println("Selector 巡查 IO 事件---------------开始");
            try {
                int ioEventCount = this.selector.select();  // 此处以收集到所有 IO 事件
                System.out.println("Selector 检测到:" + ioEventCount);
            } catch (IOException ioException) {
                ioException.printStackTrace();
                break;
            }
            // 对各个 IO 事件做出对应的响应
            Set selectionKeys = selector.selectedKeys();
            Iterator iterator = selectionKeys.iterator();

            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                iterator.remove();  //通过调用迭代器的 remove() 方法将这个键 key 从已选择键的集合中删除

                try {
                    // 可接收连接 能注册SelectionKey.OP_ACCEPT事件的只有 ServerSocketChannel通道
                    if (key.isAcceptable()) {
                        System.out.println("监控到 OP_ACCEPT 连接事件");
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();

                        // 接受客户端连接
                        SocketChannel client = server.accept();
                        System.out.println("Accept connection from " + client);
                        client.configureBlocking(false); // 设置客户端通道非阻塞
                        // 为客户端通道注册 OP_WRITE 和 OP_READ 事件
                        SelectionKey clientKey = client.register(selector,
                                SelectionKey.OP_WRITE |
                                        SelectionKey.OP_READ);
                        // 为客户端通道添加一个数据缓存区
                        ByteBuffer buffer = ByteBuffer.allocate(100);
                        clientKey.attach(buffer);
                    }
                    // 可读数据
                    if (key.isReadable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        int read = client.read(output);
                        System.out.println("Read data from client: " + client);
                        System.out.println("------------MSG : " + output.toString());
                    }
                    // 可写数据
                    if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        output.flip();
                        client.write(output);
                        output.compact();
                        System.out.println("Write data to " + client);
                    }
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }

            }

            Thread.sleep(2000);// 为了观察控制台打印数据
            System.out.println("Selector 巡查 IO 事件---------------完成");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        NIOServer nioServer = new NIOServer(DEFAULT_BIND_PORT);
        nioServer.startServer();
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/658158.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号