目录
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; /** public static void main(String[] args) throws Exception{ // 开放通道 } } } |
客户端代码 package com.shj.nio; import java.net.InetSocketAddress; /** |