美文网首页
Java NIO水平触发机制

Java NIO水平触发机制

作者: bclz | 来源:发表于2019-11-29 13:48 被阅读0次

背景: 在使用NIO通信过程中,新手往往会出现,通道关闭了或者socketChannel已经停止写数据,为什么客户端还在一直触发READ事件?

  1. 简单编写一个nio服务端和客户端通信的例子
public class SelectorExample {
    //服务端
    public static void main(String[] args) throws IOException {
        //1.创建ServerSocket,绑定端口
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(6666));
        serverSocketChannel.configureBlocking(false);  //非阻塞
        //2.创建selector,serverSocket注册selector,关心事件(接受连接准备就绪)
        Selector selector=   Selector.open();
        //关心interest事件为accept
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while(true){
            //3. select获取事件发生个数,0表示无事件
            //等待连接,阻塞1000ms
            if(selector.select(1000)==0){
//                System.out.println("1000 ms current no connect...");
                continue;
            }
            //4.获取发生事件的key列表
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                if(key.isAcceptable()){
                    //
                    dealAcceptEvent(serverSocketChannel,selector);
                }else if(key.isReadable()){

                    dealReadEvent(key);
                }else{

                    System.out.println("no interest event...");
                }
                iterator.remove();
            }

        }
    }

    private static void dealReadEvent(SelectionKey key) throws IOException {
        System.out.println("READ......");
        //通过key反向获取到socketChannel
        SocketChannel socketChannel=(SocketChannel)key.channel();
        //得到与channel关联的数据
        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
        try {
//处理读事件,这个位置暂时注掉,证明nio是条件触发
//            int read = socketChannel.read(byteBuffer);
//            if(read>0){
//                System.out.println(new String(byteBuffer.array()));
//            }
        }catch (Exception e){

            System.out.println(socketChannel.hashCode()+ "socket channel closed...");
            key.cancel();
            socketChannel.close();
        }


    }


    private static void dealAcceptEvent(ServerSocketChannel serverSocketChannel,Selector selector) throws IOException {
        System.out.println("accept...");
        SocketChannel socketChannel = serverSocketChannel.accept();
        System.out.println("socket连接...生成SocketChannel:"+socketChannel.hashCode());
        socketChannel.configureBlocking(false);
        socketChannel.register(selector,SelectionKey.OP_READ,ByteBuffer.allocate(1024));
    }
    //客户端
    public static class SocketClient{


        public static void main(String[] args) throws IOException, InterruptedException {

            SocketChannel socketChannel=SocketChannel.open(new InetSocketAddress("localhost",6666));
            socketChannel.configureBlocking(false);
//            if(!socketChannel.connect(new InetSocketAddress("localhost",6666))){
//                while (!socketChannel.finishConnect()){
//                    System.out.println("等待完成连接...");
//                }
//            }
            socketChannel.write(ByteBuffer.wrap("测试...123".getBytes("utf-8")));

            Thread.sleep(Integer.MAX_VALUE);
        }

    }

}

在server代码中读事件逻辑,我这里暂且注掉,不去读取socketchannel中的数据,运行server和client,发现client明明只write一次,server一直在触发READ事件。

\color{red}{根本原因:}server没有读取socketChannel中的数据

  1. 分享两个术语:
  • 水平触发(level-triggered,也被称为条件触发)LT: 只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你)
  • 边缘触发(edge-triggered)ET: 每当状态变化时,触发一个事件。

通过上面的试验结论: server没有读取通道里的数据或者通道数据没有全部读取完,操作系统会不断的通知selector,selector每次select的时候就一直有读事件产生。

相关文章

  • Java NIO水平触发机制

    背景: 在使用NIO通信过程中,新手往往会出现,通道关闭了或者socketChannel已经停止写数据,为什么客户...

  • epoll的水平触发和边缘触发

    参考文章:java nio使用的是水平触发还是边缘触发?参考文章:netty中的水平触发和边缘触发 我自己总结下吧...

  • java NIO详解

    Java NIO系列教程(1):Java NIO 概述 NIO学习系列:缓冲区内部实现机制 Java NIO系列教...

  • java的nio是水平触发吗

    java的nio是水平触发吗?在linux上,其实现是基于linux epoll的。所以首先我们要了解epoll。...

  • 深入分析JAVA WEB技术内幕(二)

    JAVA NIO概述 NIO的工作机制 channel和selector的概念在NIO中尤为突出。channel可...

  • java nio总结 行为分析

    参考 一篇相当全面的Java NIO教程 目的 探究nio读写何时是阻塞/非阻塞的 总结nio读写何时会触发 总结...

  • 初步认识 NIO

    1. 网络NIO Java NIO是New IO的简称,是一种可以替代Java IO的一套新的IO机制。它提供了一...

  • nio

    参考文章 Java Nio Java NIO学习笔记 - NIO客户端时序图 Java NIO学习笔记 - NIO...

  • Java Nio 之Buffer

    Java Nio 系列Java Nio 之BufferJava Nio 之直接内存Java Nio 之高级搬砖工(...

  • Java Nio 之高级搬运工(FileChannel)二

    Java Nio 系列Java Nio 之BufferJava Nio 之直接内存Java Nio 之高级搬砖工(...

网友评论

      本文标题:Java NIO水平触发机制

      本文链接:https://www.haomeiwen.com/subject/muywwctx.html