• 通道

    • 通道基础

      • 通道打开
      • 通道使用
      • 通道关闭
    • Scatter/Gather
    • 文件通道
      • 文件通道代码示例
    • Socket通道
      • Socket通道代码示例
    • 总结

通道

channel用于字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效的传输数据。
通道时一种途径,通过这种途径,可以用最小的总开销来访问操作系统本身的IO服务,缓冲区则是通道内部用于发送和接受数据的断点。

通道基础

顶层接口Channel,次级接口WritableByteChannel、ReadableByteChannel、InterruptibleChannel等。描述通道行为的接口在java.nio.channels包中定义,具体的通道实现都是从java.nio.channels.spi中的类引申来的。

通道打开

IO可以分为广义的两大类:File IO和Stream IO,对应File通道和Socket通道。体现在FileChannel类和三个socket通道类:SocketChannel、ServerSocketChannel和DatagramChannel。
代码如下:

            //打开SocketChannelSocketChannel sc = SocketChannel.open( );sc.connect (new InetSocketAddress("somehost", port));//打开ServerSocketChannelServerSocketChannel ssc = ServerSocketChannel.open( );ssc.socket( ).bind (new InetSocketAddress (port));DatagramChannel dc = DatagramChannel.open( );//FileChannel只能通过 RandomAccessFile、FileInputStream 或 FileOutputStream 对象上调用 getChannel( )方法来获取RandomAccessFile raf = new RandomAccessFile ("somefile", "r");FileChannel fc = raf.getChannel( );

通道使用

利用通道,从控制台接收输入,并在控制台打印出接收的输入。代码如下:

public static void main(String[] args) throws IOException {//一个读通道,一个写通道ReadableByteChannel source = Channels.newChannel(System.in);WritableByteChannel dest = Channels.newChannel(System.out);channelCopy(source,dest);source.close();dest.close();}private static void channelCopy(ReadableByteChannel source, WritableByteChannel dest) throws IOException{ByteBuffer byteBuffer = ByteBuffer.allocate(16 * 1024);ByteBuffer flag = ByteBuffer.allocate(4);while (source.read(byteBuffer) != -1) {byteBuffer.flip();//输出标记flag.put((byte)'-').put((byte)'-').put((byte)'-').put((byte) '>');flag.flip();dest.write(flag);dest.write(byteBuffer);flag.clear();byteBuffer.compact();}byteBuffer.flip();//确保缓冲区排干净while (byteBuffer.hasRemaining()) {flag.putChar('-').putChar('-').putChar('-');flag.flip();dest.write(byteBuffer);flag.clear();}}

测试输入输出如下:

通道关闭

与缓冲区不同,通道不能重复利用,打开通道即代表与一个特定的IO服务的特定链接并封装该链接的状态,通道关闭时,连接丢失,通道不在连接任何东西。
调用close方法时,可能导致线程暂时阻塞,关闭的通道上调用close方法不会产生任何操作,只会立即返回。可以通过isOpen方法判断通道状态。
如果一个线程被中断,那么这个线程访问的通道将立即关闭,这也是为程序健壮性而采用的一种权衡。

Scatter/Gather

在多个缓冲区实现一个简单的IO操作:
对于write,数据是从几个缓冲区按顺序抽取(gather)并沿着通道发送。该gather过程,好比全部缓冲区内容被连接起来,并在发送前存放到一个大的缓冲区。
对于read,从通道读取的数据会被按顺序散布(scatter)到多个缓冲区,将每个缓冲区填满直至通道中的数据或缓冲区的空间被消耗完。
接口定义如下, 其中read和write入参时Buffer数组:

public interface ScatteringByteChannelextends ReadableByteChannel
{public long read (ByteBuffer [] dsts)throws IOException;public long read (ByteBuffer [] dsts, int offset, int length)throws IOException;
}
public interface GatheringByteChannelextends WritableByteChannel
{public long write(ByteBuffer[] srcs)throws IOException;public long write(ByteBuffer[] srcs, int offset, int length)throws IOException;
}

文件通道

具体来讲FileChannel,接口如下:

public abstract class FileChannelextends AbstractInterruptibleChannelimplements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel

FileChannel 对象是线程安全(thread-safe)的.
对于文件IO,最强大之处在于异步IO,它允许一个进程可以从操作系统请求一个或多个IO操作而不必等待这些操作完成。

文件通道代码示例

  • 将缓冲区数据,通过文件channel写入文件
    public static void write(String filePath) throws Exception {/*写文件,使用FileOutputStream,RandomAccessFile都可以。*/
/*      RandomAccessFile file = new RandomAccessFile(filePath,"rw");*/FileOutputStream file = new FileOutputStream(new File(filePath));ByteBuffer byteBuffer = ByteBuffer.allocate(500);String str = "hello LK";/*数据写入缓冲区*/byteBuffer.put(str.getBytes());byteBuffer.flip();FileChannel fileChannel = file.getChannel();//将缓冲区数据写入文件通道fileChannel.write(byteBuffer);byteBuffer.clear();fileChannel.close();}
  • 通过文件channel,将文件中的数据读入缓冲区
    public static void read(String filePath) throws Exception {FileInputStream fileInputStream = new FileInputStream(new File(filePath));/*一个FileChannel对象却只能通过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream对象上调用getChannel()方法来获取,开发者不能直接创建一个FileChannel*/FileChannel fileChannel = fileInputStream.getChannel();ByteBuffer byteBuffer = ByteBuffer.allocate(500);//将文件channel读入缓冲区fileChannel.read(byteBuffer);byteBuffer.flip();while (byteBuffer.hasRemaining()){System.out.print((char)byteBuffer.get());}byteBuffer.clear();fileChannel.close();}

Socket通道

新的Socket通道类可以运行非阻塞模式,并且是可选择的。借助新的NIO类,一个或几个线程可以管理成百上千的活动socket连接,并且只有很少的性能顺势。
全部 socket 通道类(DatagramChannel、SocketChannel 和 ServerSocketChannel)都是由位于java.nio.channels.spi 包中的AbstractSelectableChannel引申而来。
DatagramChannel 和 SocketChannel 实现定义读和写功能的接口而 ServerSocketChannel 不实现。ServerSocketChannel 负责监听传入的连接和创建新的SocketChannel 对象,它本身从不传 输数据。

Socket通道代码示例

启动一个ServerSocketChannel,监听8001端口,非阻塞模式。启动10个SocketChannel线程向ServerSocketChannel写数据。
ServerSocketChannel代码如下:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();/*非阻塞*/serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(new InetSocketAddress(port));System.out.println("ServerSocketChannel is OK,waiting @[" + LocalDateTime.now() + "]");for (; ; ) {SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel == null) {Thread.sleep(1000);System.out.println("ServerSocketChannel sleep 1000ms.");continue;}String connectIP = socketChannel.socket().getRemoteSocketAddress().toString();System.out.println("客户端已有数据到来,客户端ip为:" + connectIP + ", 时间为" + LocalDateTime.now());ByteBuffer byteBuffer = ByteBuffer.allocate(1024);socketChannel.read(byteBuffer);byteBuffer.flip();while (byteBuffer.hasRemaining()) {System.out.print((char) byteBuffer.get());}socketChannel.close();}}

启动10个SocketCHannel代码如下:

private static final int port = 8001;public static void main(String[] args) {for (int i=0;i<10;i++) {new SocketChannelImpl(port,i).start();}}private static class SocketChannelImpl extends Thread {private  int count = 0;private int port;public SocketChannelImpl(int port,int count){this.port = port;this.count = count;}@Overridepublic void run() {try {SocketChannel socketChannel = SocketChannel.open();/*非阻塞*/socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress(port));for (;!socketChannel.finishConnect();) {System.out.println("connectting....");Thread.sleep(50);}ByteBuffer byteBuffer = ByteBuffer.allocate(1024);String content = "hello, i am client--------->" + count;byteBuffer.put(content.getBytes());byteBuffer.flip();socketChannel.write(byteBuffer);byteBuffer.clear();socketChannel.close();} catch (Exception e) {e.printStackTrace();}}}

运行结果如下:

补充下:
ServerSocketChannel监听的是8001端口,你可以在浏览器,输入:http://localhost:8001/helloworld,你会发现你的ServerSocketChannel也是可以收到数据了,这也web服务器处理的基础了。

总结

以上,了解了基本的通道操作,文件通道和socket通道的使用示例,我觉得点个赞,不过分=。=
以上所有代码示例,可以fork这里:github

谢谢

转载于:https://www.cnblogs.com/lknny/p/9096212.html

Java NIO之通道相关推荐

  1. 03. Java NIO Channel 通道

    2019独角兽企业重金招聘Python工程师标准>>> Java NIO Channel通道和流非常相似,主要有以下几点区别: 通道可以度也可以写,流一般来说是单向的(只能读或者写) ...

  2. Java NIO之Channel(通道)

    **Java高级特性增强-NIO 本部分网络上有大量的资源可以参考,在这里做了部分整理并做了部分勘误,感谢前辈的付出,每节文章末尾有引用列表~ 写在所有文字的前面:作者在此特别推荐Google排名第一 ...

  3. Java NIO系列教程(二) Channel

    为什么80%的码农都做不了架构师?>>>    Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写 ...

  4. Java NIO 系列教程 转

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  5. Java NIO 系列教程

    Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO. Java NIO提供了与 ...

  6. 我所理解的Java NIO

    这两天了解了一下关于NIO方面的知识,网上关于这一块的介绍只是介绍了一下基本用法,没有系统的解释NIO与阻塞.非阻塞.同步.异步之间的联系,导致自己困扰了好久.本篇文章就个人关于NIO的理解进行阐述. ...

  7. 你对Java网络编程了解的如何?Java NIO 网络编程 | Netty前期知识(二)

    本文主要讲解NIO的简介.NIO和传统阻塞I/O有什么区别.NIO模型和传统I/O模型之间的对比.以及围绕NIO的三大组件来讲解,理论代码相结合. 很喜欢一句话:"沉下去,再浮上来" ...

  8. 精讲Java NIO

    Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本文将有助于你学习和理解Java NIO. Java NIO提供了与标准I ...

  9. Java NIO学习篇之NIO的基本认识

    定义: NIO:是从jdk1.4提出的,本意是New IO(相对于传统的IO),也叫 No Blocked IO(只相对于网络IO),它的出现弥补传统IO的不足,提出了更加高效的方式. NIO对于网络 ...

最新文章

  1. 调查:中国内地受访者每年花约40天用于各种“等”
  2. 【原创】.NET读写Excel工具Spire.Xls使用(4)对数据操作与控制
  3. 高等数学:第三章 微分中值定理与导数的应用(2)函数单调性 极值 最大值 最小值
  4. MemSQL初体验 - (2)初始化测试环境
  5. es内嵌文档查询_ElasticSearch 文档的增删改查都不会?
  6. VS2019/openGL/freeglut配置
  7. bgb邻居关系建立模型_今日 Paper | 新闻推荐系统;多路编码;知识增强型预训练模型等...
  8. 响应式下的雪碧图解决方案 - 活用background-size / background-position
  9. oracle11g ADR 位置
  10. bzoj 1295: [SCOI2009]最长距离(SPFA)
  11. VB-ocx应用于Web
  12. sqlite迁移mysql(导入导出数据)
  13. paip.提升效率---质量控制--代码风格模板化
  14. 伸缩Kubernetes到2500个节点中遇到的问题和解决方法
  15. 实现类似shared_ptr的引用计数
  16. segnet和unet区别_SegNet图像分割网络直观详解
  17. 计算机c和用户名是什么意思啊,计算器AC.C是什么意思?
  18. JHU计算机专业学费,约翰霍普金斯大学学费多少 贵不贵
  19. three.js 源码注释(六十一)objects/LOD.js
  20. 「设计模式(二) - 观察者模式」

热门文章

  1. ubuntu/deepin常用软件清单(都是使用sudo apt-get install安装方式)
  2. 【学亮说】Java实现单例模式的8种方式(你真的搞懂单例模式了吗?)
  3. Java客户端操作zookeeper:获取及修改节点中的数据内容代码示例
  4. Python Django 生成随机字符串UUID的使用示例
  5. Hadoop大数据--Mapreduce编程规范及入门示例
  6. Scala中的trait特质
  7. 【比较面】真核生物和原核生物的异同
  8. 基于vue和vuex的todos效果展示及源码分享
  9. creo扫描选择多条链作为轨迹_ProE/Creo圆轨迹可变扫描法创建弧顶面,用上便爱上(一)...
  10. sql优化的方法及思路_合理的sql优化思路--如何缩短SQL调优时间?