java NIO相关知识点 (1)

目录

 

NIO中的几个重要概念

 1 通道 Channel

2 缓冲区

3 选择器


NIO中的几个重要概念

通道,缓冲区,选择器

 1 通道 Channel

类似于流,但是通道是双向的,而流是单向的

通道支持异步读写数据,流只能同步读写

通道的数据总是要先读到一个buffer或者从一个buffer写入.

常用的通道有4种

FileChannel 从文件中读写

DatagramChannel   从UDP中读写网络中的数据

SocketChannel  能通过TCP读写网络中的数据

ServerSocketChannel   可以监听新进来的TCP连接

2 缓冲区 (buffer)

buffer主要负责与通道进行交互,本质上是一块可以存储数据的内存,被封装buffer对象,这块内存被封装成NIO Buffer 对象,并提供了一组方法,用来方便的访问zhek这块内存. Buffer有7个子类,用来存储不同的数据类型的数据,分别是:

ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer ,都是针对基本数据类型,没有针对布尔型的

缓冲区有4个最主要的属性: capacity ,limit,position.mark

capacity 缓冲区可容纳的最大数据量,在创建缓冲区是已确定,不能更改
limit 限制,limit之后的内容无法进行读写操作
position 指的是下一个进行读/写的索引
mark 标记,mark()设置mark=position,再调用reset() 恢复到标记位置,使得position=mark

一般从buffer中读写数据需要经历以下步骤

1 将数据写入缓冲区

2 调用flip()   ,flip的作用是对缓冲区中的数据部分进行操作

附上flip()的源代码  

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

3 从缓冲区中拿到数据

4 调用clear()  clear的作用是把可以把当前的缓冲区当做一个新的缓冲区来使用

clear()源代码

  public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

3 选择器(selector)

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。 
仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。selector在使用时通道必须处于非阻塞状态,所以不能与FileChannel一起使用,因为fileChannel不能切换到非阻塞状态,

实例1 缓冲区的使用(buffer)

public static void byteBufferTest() {
        
//        为缓冲区分配空间
        ByteBuffer buffer =ByteBuffer.allocate(30);

        buffer.put("hero_孙".getBytes());
//        System.out.println(buffer);//java.nio.HeapByteBuffer[pos=8 lim=30 cap=30]
        buffer.flip();
//        System.out.println(buffer); //java.nio.HeapByteBuffer[pos=0 lim=8 cap=30]
        System.out.println(new String(buffer.array(),0,buffer.limit()));
        buffer.clear();
//    System.out.println(buffer); //java.nio.HeapByteBuffer[pos=0 lim=30 cap=30]
    
    }

实例2 FileChannel的使用(文件读写)

public static void  NIOFileReadAndWrite(String inName , String outName) throws Exception{
        
        FileInputStream fis=new FileInputStream(new File(inName));
//        创建通道
            FileChannel fisChannel=fis.getChannel();
            
        FileOutputStream fos=new FileOutputStream(new File(outName));
//        创建通道
        FileChannel foschannel=fos.getChannel();
//        创建缓冲区
        ByteBuffer buffer =ByteBuffer.allocate(1024);
    
        while( fisChannel.read(buffer)!=-1) {
            buffer.flip();
             while(foschannel.write(buffer)!=0) {
                 
             }
             buffer.clear();
        }
        
        if(fis!=null) {
            fis.close();
        }
        if(fos!=null) {
            fos.close();
        }
        if(fisChannel!=null) {
            fisChannel.close();
        }
        if(foschannel!=null) {
            foschannel.close();
        }
    }

实例3 客户端,服务器的使用(TCP)

服务器代码

package com.shj.nio;

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

/**
 * 服务端
 *@Description:
 *@author shj
 *@ClassName:     NIOServer.java
 *@Date           2018年7月19日 上午10:50:57 
 *
 */
public class NIOServer {

    public static void main(String[] args)  throws Exception{

//        开放通道
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
         serverSocketChannel.socket().setReuseAddress(true);
//        绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(888));
        
//        设置非阻塞
        serverSocketChannel.configureBlocking(false);
//        选择器
        Selector selector =Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器等待连接...");
        while(true) {
            
            if(selector.select()==0) {
                continue;
            }
        
            Iterator<SelectionKey> ite=selector.selectedKeys().iterator();
            
            while(ite.hasNext()) {
                SelectionKey selectionKey =ite.next();
                
                   //如果满足Acceptable条件,则必定是一个ServerSocketChannel
                if(selectionKey.isAcceptable()){
                    ServerSocketChannel sscTemp = (ServerSocketChannel) selectionKey.channel();
                    //得到一个连接好的SocketChannel,并把它注册到Selector上,兴趣操作为READ
                    SocketChannel socketChannel = sscTemp.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);

                }
                
                //如果满足Readable条件,则必定是一个SocketChannel
                if(selectionKey.isReadable()) {
//                获取到通道
                    SocketChannel sockerChannel=(SocketChannel) selectionKey.channel();
                    if(sockerChannel!=null) {
                        System.out.println("已有客户端连接上来");
                        ByteBuffer buffer=ByteBuffer.allocate(100);
                        
                        while(sockerChannel.read(buffer)!=-1) {
//                            
                            buffer.flip();
                            System.out.println("服务器接收到数据-->"+new String(buffer.array(),0,buffer.limit()));
                            buffer.clear();
                            Thread.sleep(1000);
//                            向客户端回复内容
                            buffer.put((new Date()+"服务器").getBytes());
                            
                            buffer.flip();
                            sockerChannel.write(buffer);
                            buffer.clear();
                        }
                        
                    }
                    
                    
                }
                
                
                ite.remove();
            }
            
        }
    
    
    

    }

}
 

客户端代码

package com.shj.nio;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
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.Date;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * 客户端
 *@Description:
 *@author shj
 *@ClassName:     NIOClient.java
 *@Date           2018年7月19日 上午10:51:12 
 *
 */
public class NIOClient {

    
    public static void main(String[] args) throws Exception{
        
        SocketChannel socketChannel =SocketChannel.open();
//        设置非阻塞
        socketChannel.configureBlocking(false);
//        请求连接
        socketChannel.connect(new InetSocketAddress("127.0.0.1",888));
        
          while (!socketChannel.finishConnect()) {
              TimeUnit.MILLISECONDS.sleep(100);
          }
        
          while(true) {
              ByteBuffer buffer=ByteBuffer.allocate(100);
              System.out.println("已连接到服务器");
              
              while(socketChannel.read(buffer)!=-1) {
                  buffer.flip();
                  System.out.println("客户端收到的信息-->"+new String(buffer.array(),0,buffer.limit()));
                  buffer.clear();
                  
                  Thread.sleep(1000);                  
//                  回复数据
                  buffer.put((new Date()+"客户端1").getBytes());
                  buffer.flip();
                  socketChannel.write(buffer);
                  buffer.clear();
                  
              }
              
          }
        
    }
}
 

 



 

猜你喜欢

转载自blog.csdn.net/aa15237104245/article/details/80987406