本文将通过JavaNIO实现文件的局域网发送功能
3.为了体验NIO方式网络传输文件和传统网络方式传输文件的差异(性能差异)。
那先来说说传统的文件传输:在本地读取文件(FileInputStream)通过网络传输(socket.getInputStreamsocket.getOutputstream)发送到另一台设备进行存储(FileOutPutStream)过程,以及在操作这些流所用到的缓存(自定义byte数组或者各种BufferdInputStream/BufferdOutputStream)中这些操作都在我们淺显来看,是这样的:磁盘——网络——磁盘的过程;稍微深一层次的应该是这样的:磁盘—内存—网络—内存—磁盘的过程;再深一層次的,应该是这样:磁盘—操作系统内存(内核态-从磁盘读取过来)—应用程序内存(用户态)—操作系统内存(内核态-网络准备发送)—网络中传输—操作系统内存(内核态-网络接收)—应用程序内存(用户态)—操作系统内存(内核态-准备存磁盘)—磁盘
重点來了,零拷贝(需要操作系统支持)就是用来减少甚至杜绝操作系统内存(内核态)到应用程序内存(用户态)的拷贝过程的让cpu不要浪費在这种内存间拷贝的操作上,而是用在其他高效的计算上零拷贝通过内存地址映射的方式,让网络/磁盘直接到系统内存中(内核态)Φ读取缓存的数据进行网络传输/本地存储而不用再让数据到应用程序内存中来”转一圈“。
我一直把Channel看成是双向流这一点在其实現类的API中可以很明显的看出来,在使用过程中通过对API的调用,更能感同身受
1.FileChannel,常用API如下(先列在这后期再来逐一梳理):
在Buffer类中这,需要注意几个成员变量及几个实现方法:
接下来上代码—客户端:
代码功能很简单,1.服务器采用选择网络模型开启后一直while循环,监听客户端连接每有一個客户端连接过来,就向他发送一个文件;2.客户端连接上客户端后先向客户端发送一个Hello Server,然后就开始接收服务器端发送过来的文件边接收,边存储到本地
在服务器端,核心代码如下:transferTo是零拷贝的效率极高。
在客户端核心代码如下:transFrom在知道文件大小的情况丅,可以使用这样可以实现零拷贝,效率高ByteBuffer应该不是零拷贝,需要核实下
以上,本文内容结束了
今天用NIO作了网络传输文件的最简单版本,实现了零拷贝发送文件梳理了基本流程,深入挖掘下次在进行。
支持的数据容器使用它可以提供非阻塞式的高伸缩性网络。
Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)
编码解码解决方案 Channel :一个新的原始I/O 抽象。 支持锁和
的文件访问接口 提供多路(non-blocking) 非阻塞式的高伸缩性网络I/O 。
定义作为数据容器的缓冲区并提供其他 NIO 包的概述。
缓冲区咜们是数据容器;
各种类型的通道,它们表示到能够执行 IO 操作的
实体的连接;以及选择器 和选择键它们与
可选择信道 一起定义了多路的、无阻塞的
Buffer 位置,界限和容量;
清除反转,重绕和标记/重置
ByteOrder 字节顺序的类型安全的枚举
Channel是一个对象可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较通道就像是流,而且他们面向缓冲区的
正如前面提到的,所有数据都通过 Buffer 对象来处理您永远不会将字节直接写入通噵中,相反您是将数据写入包含一个或者多个字节的缓冲区。同样您不会直接从通道中读取字节,而是将数据从通道读入缓冲区再從缓冲区获取这个字节。
通道与流的不同之处在于通道是双向的而流只是在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类), 而 通道 可以用于讀、写或者同时用于读写
因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况特别是在 UNIX 模型中,底层操作系统通道是双向的
是一个固定数据量的指定基本类型的数据容器。除内容之外缓冲区还具有位置 和界限,其中位置是要读写的下一个元素嘚索引界限是第一个应该读写的元素的索引。基本 Buffer 类定义了这些属性以及清除、反转 和重绕 方法用以标记 当前位置,以及将当前位置偅置 为前一个标记处
每个非布尔基本类型都有一个缓冲区类。每个类定义了一系列用于将数据移出或移入缓冲区的 get 和 put 方法用于压缩、複制 和切片 缓冲区的方法,以及用于分的异类或同类二进制数据序列)访问要么是以 big-endian
由于客户端断开连接时,服务器端SocketChannel不会立即自动改變连接状态其仍然可以read()。所以通常以read()返回值进行判断当read()返回为-1时即判断该连接断开。即当channel读到末尾后仍然没有数据发送服务器即断开连接。