zoukankan      html  css  js  c++  java
  • java NIO基础

    推荐资料: https://tech.meituan.com/2016/11/04/nio.html

    Java I/O 分类

    • 磁盘操作:File
    • 字节操作:InputStream 和 OutputStream
    • 字符操作: Writer 和 Reader
    • 对象操作:Serializable
    • 网络操作:Socket
    • 新的输入/输出:NIO

    来源-极客时间

    NIO

    (1)通道(Channel)

    通道 Channel 是对原 I/O 包中的流的模拟,Channel 本身不能直接访问数据,Channel 只能与Buffer 进行交互。

    通道与流的不同之处在于,流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同时用于读写。

    通道包括以下类型:

    • FileChannel:从文件中读写数据;
    • DatagramChannel:通过 UDP 读写网络中数据;
    • SocketChannel:通过 TCP 读写网络中数据;
    • ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
    (2)缓冲区(Buffer)

    发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。

    缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。

    除了布尔类型,所有原始数据类型都有相应的 Buffer 实现

    直接与非直接内存
    • 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中。适用于并发连接数少于1000,I/O操作较少

    • 直接字节缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。适用于数据量比较大,生命周期比较长

    • allocateDirect()方法返回的DirectByteBuffer就是与底层存储空间关联的缓冲区,它通过Native代码操作非JVM堆的内存空间,每次创建或者释放的时候都调用System.gc()。注意,使用DirectByteBuffer时可能会引起JVM内存泄漏的问题。

    • 字节缓冲区是直接缓冲区还是非直接缓冲区通过调用其 isDirect() 方法确定。

    (3)选择器(Selector)

    NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。
    Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。这样,一个单独的线程可以管理多个Channel,从而管理多个网络连接。

    Linux 上依赖于 epoll实现-源码

    NIO使用实例

    public class NIOTest {
    
    	public static void main(String[] args) throws IOException {
    		//创建选择器
    		Selector selector = Selector.open();
    		//将通道注册到选择器上
    		ServerSocketChannel ssChannel = ServerSocketChannel.open();
    		ssChannel.configureBlocking(false);
    		ssChannel.register(selector, SelectionKey.OP_ACCEPT);
    
    		ServerSocket serverSocket = ssChannel.socket();
    		InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
    		serverSocket.bind(address);
    
    		while (true) {
    			//一次 select()调用不能处理完所有的事件,并且服务器端有可能需要一直监听事件
    			//因此服务器端处理事件的代码一般会放在一个死循环内。
    			selector.select();
    			Set<SelectionKey> keys = selector.selectedKeys();
    			Iterator<SelectionKey> keyIterator = keys.iterator();
    
    			while (keyIterator.hasNext()) {
    				SelectionKey key = keyIterator.next();
    				if (key.isAcceptable()) {
    					ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
    					// 服务器会为每个新连接创建一个 SocketChannel
    					SocketChannel sChannel = ssChannel1.accept();
    					sChannel.configureBlocking(false);
    					// 这个新连接主要用于从客户端读取数据
    					sChannel.register(selector, SelectionKey.OP_READ);
    				} else if (key.isReadable()) {
    					SocketChannel sChannel = (SocketChannel) key.channel();
    					System.out.println(readDataFromSocketChannel(sChannel));
    					sChannel.close();
    				}
    				keyIterator.remove();
    			}
    		}
    	}
    
    	private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
    		ByteBuffer buffer = ByteBuffer.allocate(1024);
    		StringBuilder data = new StringBuilder();
    
    		while (true) {
    			buffer.clear();
    			int n = sChannel.read(buffer);
    			if (n == -1) {
    				break;
    			}
    			buffer.flip();
    			int limit = buffer.limit();
    			char[] dst = new char[limit];
    			for (int i = 0; i < limit; i++) {
    				dst[i] = (char) buffer.get(i);
    			}
    			data.append(dst);
    			buffer.clear();
    		}
    		return data.toString();
    	}
    }
    
    public class NIOClient {
    	public static void main(String[] args) throws IOException {
    		Socket socket = new Socket("127.0.0.1", 8888);
    		OutputStream out = socket.getOutputStream();
    		String s = "Hello world";
    		out.write(s.getBytes());
    		out.close();
    	}
    }
    
  • 相关阅读:
    LDAP2-创建OU创建用户
    GNE: 4行代码实现新闻类网站通用爬虫
    为什么每一个爬虫工程师都应该学习 Kafka
    新闻网页通用抽取器GNEv0.04版更新,支持提取正文图片与源代码
    写了那么久的Python,你应该学会使用yield关键字了
    新闻类网页正文通用抽取器
    为什么Python 3.6以后字典有序并且效率更高?
    为什么你需要少看垃圾博客以及如何在Python里精确地四舍五入
    数据工程师妹子养成手记——数据库篇
    一行js代码识别Selenium+Webdriver及其应对方案
  • 原文地址:https://www.cnblogs.com/flyuz/p/11408437.html
Copyright © 2011-2022 走看看