NIO-概览
NIO-Buffer
NIO-Channel
NIO-Channel接口分析java
原本是想学习Netty的,可是Netty是一个NIO框架,所以在学习netty以前,仍是先梳理一下NIO的知识。经过剖析源码理解NIO的设计原理。windows
本系列文章针对的是JDK1.8.0.161的源码。微信
通道(Channel)是对原I/O包中的流的模拟。与文件设备I/O交互的全部数据都必须经过一个Channel对象。网络
上一节咱们提到在NIO中使用缓冲区来存放指定基元的数据,咱们能够经过Buffer来读写数据。
将数据写入到硬盘时,咱们能够将字节数据写入到缓冲区中;若咱们要从硬盘读取数据,则须要经过通道将数据写入到缓冲区,而后再从缓冲区读取数据。框架
根据不一样的使用方式,分为不一样的通道。好比咱们须要网络读写,就须要网络交互的通道。须要文件读写就须要文件交互的通道。
NIO实现了Sctp协议、TCP协议、UDP协议以及文件传输四种通道,同时还实现了Windows平台的异步Socket通道以及异步文件通道。dom
windows平台的异步I/O是经过重叠I/O和IOCP(I/O完成端口)实现的,想要了解windows异步I/O的知识能够看一下我另外一篇文章《Windows内核原理-同步IO与异步IO》异步
类型 | 通道 |
---|---|
Sctp协议客户端 | SctpChannel |
Sctp协议多播客户端 | SctpMultiChannel |
Sctp协议服务端 | SctpServerChannel |
UDP协议 | DatagramChannel |
TCP协议同步I/O服务端 | ServerSocketChannel |
TCP协议同步I/O客户端 | ServerChannel |
文件读写 | FileChannel |
对于Windows平台的异步通道socket
类型 | 通道 |
---|---|
TCP协议异步I/O服务端 | WindowsAsynchronousServerSocketChannel |
TCP协议异步I/O客户端 | WindowsAsynchronousSocketChannel |
异步文件读写 | WindowsAsynchronousFileChannel |
另外NIO还实现了一个单向通信管道(Pipe)的功能,经过引入
SourceChannel
和SinkChannel
实现,底层实际仍是Socket通信。学习
在介绍不一样的Channel的实现以前咱们先介绍下Channel如何使用。
以TCP协议为例,咱们进行网络收发的时候,首先须要建立一个ServerSocketChannel用于监听端口。
//建立一个服务端socket通道用于接收链接 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //绑定监听地址 serverSocketChannel.socket().bind(new InetSocketAddress(8080)); //等待链接 SocketChannel socketChannel = serverSocketChannel.accept();
咱们监听了8080端口。若没有链接时,线程会阻塞在
accept
。
当有收到新的链接建立时,会获取到SocketChannel,此时咱们须要建立一个Buffer用来从Channel中读取数据。
ByteBuffer buf = ByteBuffer.allocate(1024); //数据将写入到buffer中 int length = socketChannel.read(buf);
数据写入到咱们的Buffer中,咱们就须要将他们读出来
buf.flip(); //转化为可读模式 byte[] data = new byte[length]; buf.get(data);
将数据从Buffer写入到Channel时
buf.clear(); byte[] resp = {'O','K'}; buf.put(resp); buf.flip();//转换为读模式 socketChannel.write(buf);
这里为了方便直接使用原来的Buffer。
做为客户端咱们须要建立一个SocketChannel。
SocketChannel.open(); client.connect(new InetSocketAddress("127.0.0.1", 6060));
发送HELLO
给服务端
ByteBuffer buffer = ByteBuffer.allocate(10); byte[] data = {'H', 'E', 'L', 'L', 'O'}; buffer.put(data); buffer.flip();//转换为读模式 client.write(buffer);
阻塞等待读取数据
buffer.clear(); client.read(buffer); buffer.flip();//转换为读模式
处理完成,须要关闭释放链接
//关闭客户端输入流 client.socket().shutdownInput(); //关闭客户端输出流 client.socket().shutdownOutput(); //关闭客户端socket时会关闭客户端channel client.socket().close(); //关闭客户端channel,会同时关闭输入和输出流。 client.close();
关闭输出流会发送FIN包,若输入流未关闭仍然能够继续接收数据,这就是TCP的半链接。若处理完最后须要确保channel关闭。
FileChannel只能被FileInputStream、FileOutputStream、RandomAccessFile建立
使用RandomAccessFile
建立FileChannel
//第一个参数时文件名,第二个参数是读写方式 RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt","rw"); FileChannel channel = randomAccessFile.getChannel();
使用RandomAccessFile
建立FileChannel
FileInputStream inputStream = new FileInputStream("1.txt"); channel = inputStream.getChannel();
inputStream获取的FileChannel只能读
使用RandomAccessFile
建立FileChannel
FileOutputStream outputStream = new FileOutputStream("1.txt"); channel = outputStream.getChannel();
inputStream获取的FileChannel只能写
关闭FileChannel的方法和关闭SocketChannel方法同样。
//关闭channel时会关闭文件 channel.close(); //关闭文件时会关闭channel randomAccessFile.close(); //关闭文件流时会关闭channel inputStream.close(); //关闭文件流时会关闭channel inputStream.close();
因为源码解析的篇幅较长,所以将channel源码单独分出来说解。
微信扫一扫二维码关注订阅号杰哥技术分享
出处:http://www.javashuo.com/article/p-pwariqtr-gr.html 做者:杰哥很忙 本文使用「CC BY 4.0」创做共享协议。欢迎转载,请在明显位置给出出处及连接。