java——nio(学习笔记)

buffer

    public static void method1(){
        RandomAccessFile aFile = null;
        try{
            aFile = new RandomAccessFile("src/nio.txt","rw");
            FileChannel fileChannel = aFile.getChannel();
            ByteBuffer buf = ByteBuffer.allocate(1024);
            int bytesRead = fileChannel.read(buf);
            System.out.println(bytesRead);
            while(bytesRead != -1)
            {
                buf.flip();
                while(buf.hasRemaining())
                {
                    System.out.print((char)buf.get());
                }
                buf.compact();
                bytesRead = fileChannel.read(buf);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(aFile != null){
                    aFile.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

我们可以从代码中大体猜到

  1. buffer需要分配空间
  2. 从channel中write buffer中
  3. buffer调用flip方法转变为read模式
  4. 调用buffer到get方法进行读操作
  5. 调用compact方法或者clean方法进行对buffer对清除
    在这里插入图片描述
    以上图就是对buffer对写和读。
    写模式中就随着数据的写入,position的位置会跟着改变。
    如果转变到读模式,limit会跳转到position到位置,position会跳到最开始到地方。
    如果进行compact到话,只是改变limit到位置到capacity的位置,而不对buffer里面的数据进行清除。

channel

			serverSocket = new ServerSocket(8080);
            int recvMsgSize = 0;
            byte[] recvBuf = new byte[1024];
            while(true){
                Socket clntSocket = serverSocket.accept();
                SocketAddress clientAddress = clntSocket.getRemoteSocketAddress();
                System.out.println("Handling client at "+clientAddress);
                in = clntSocket.getInputStream();
                while((recvMsgSize=in.read(recvBuf))!=-1){
                    byte[] temp = new byte[recvMsgSize];
                    System.arraycopy(recvBuf, 0, temp, 0, recvMsgSize);
                    System.out.println(new String(temp));
                }
            }

使用bio的写法,就是创建serverSocket,并在循环中调用accept()方法,等待连接。这里的等待是阻塞的,即线程会被挂起,直到有连接才会对线程进行唤醒。

如果使用NIO的方法

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9999));
        serverSocketChannel.configureBlocking(false);
        while (true)
        {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel != null)
            {
                // do something with socketChannel...
            }
        }

我们设置了configureBlocking为false的话,serverSocketChannel.accept() 马上会有返回值。
没有连接的话,则是null。所以我们也需要在循环中对这个方法进行调用,和bio不同的是,线程不会被挂起,但是资源会被浪费。

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.println("==");
                    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.isWritable() && key.isValid()){
                        handleWrite(key);
                    }
                    if(key.isConnectable()){
                        System.out.println("isConnectable = true");
                    }
                    iter.remove();
                }
            }
        }

这里的ServerSocketChannel注册进了selector中并且注册了对连接“感兴趣”,一个selector可以拥有多个channel。
但是selector的accept()该方法会阻塞等待,直到有一个或更多的信道准备好了I/O操作或等待超时。
select()方法将返回可进行I/O操作的信道数量。
在一个单独的线程中,通过调用select()方法就能检查多个信道是否准备好进行I/O操作。
如果经过一段时间后仍然没有信道准备好,select()方法就会返回0,并允许程序继续执行其他任务。

Iterator<SelectionKey> iter = selector.selectedKeys().iterator();

访问“已选择键集(selected key set)”中的就绪通道。
对这个键集进行遍历,并处理相映对io事件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值