Java NIO
字节缓冲区
字节顺序-大端-小端
ByteOrder.nativeOrder().toString() 获取当前处理器的字节顺序
直接缓冲区
ByteBuffer.allocateDirect() 创建所需容量的直接缓冲区
isDirect() 是否直接缓冲区
只有字节类型数据才可以创建直接缓冲区,其他类型可使用视图缓冲区
ByteBuffer.asCharBuffer() 根据字节直接缓冲区创建一个字符直接缓冲区
视图缓冲区
与源缓冲区操作地址一致,但position\limit 等标识可不一致。
byteBuffer.as***() 此类操作以字节顺序包装为指定缓冲区
duplicate()
slice()
通道
通道是途径,是抽象的概念,受控的且可移值的方式来访问操作系统底层I/O
- 文件通道
- Socket通道
阻塞、非阻塞
打开通道
FileChannel.getChannle()
SocketSchannel.getChannel()
关闭通道
通道是无法重复使用的
中断阻塞在通道上的线程会自动关闭通道
channel.close(); 在网络上可能是阻塞的(在内容被提取前,部分框架可能会阻塞通道关闭)
Scatter/Gather(发散/收集)
以Channel为视角,channel.writer(Buffer[] ) 。channel.read(Buffer[])
通道接收多个缓冲区,将多个缓冲区内容“Gather”到通道。
将通道内容“Scatter”到多个缓冲区。
这个过程是顺序的。也是高效的(由操作系统直接完成)。
buffer--\ channel / buffer
buffer----Scatter ======= Gather------buffer
buffer--/ \ buffer
文件通道
FileChannel
read()/write()方法会改变Position位置,同一文件的多个对象是共享Position的(由操作系统控制)。
read(p)/write(p) 这个是不共享的。
将position位置移动到大于文件size的位置,调用write()可能会照成 "文件空洞"。
truncate() 会去除超出的size值,并将position = size
force(boolean) 类似刷盘的操作,强制将文件内容写入磁盘。参数标识是否将文件元数据强制写入。
文件锁
不支持共享锁的操作系统自动升级到独享锁。
锁的对象是文件,而不是通道或者缓冲区。
锁判断的是进程而不是线程,意味着同一Java进程获取到锁后同一进程都能获取到锁。
FileChannel.lock(position,size, shared) 锁定position-size位置,shared标识是否共享。
channel关闭、FileLock.release()、进程关闭会释放锁。
FileLock.isVaild() 校验锁是否有效。
避免死锁。
内存映射文件
MapperByteBuffer 将物理磁盘中的文件直接在程序中操作。
load()
isLoaded()
force() 与FileChannel.force()一样
transferto/transferForm 通道间文件数据传输,有一端必须为FileChannel。传输当前通道已有数据到另一通道。不经过用户空间。
Socket通道
ServerSocketChannel
- open()
- socket()
- accept()
- vaildOps()
SocketChannel
@Test
public void ser() throws Exception {
SocketChannel socketChannel = SocketChannel.open();
// 设置非阻塞模式
socketChannel.configureBlocking(false);
// 链接
// 链接一旦被打开只有结束才可以关闭
// 非阻塞模式下调用 connect 会立即返回信息,如果无法立即建立链接则返回false并继续建立链接
System.out.println("start.....");
socketChannel.connect(new InetSocketAddress("127.0.0.1", 3306));
/**
* finishConnect() 操作可能触发的事情
* connect( )方法尚未被调用。那么将产生 NoConnectionPendingException 异常。 连接建立过程正在进行,尚未完成。那么什么都不会发生,finishConnect( )方法会立即返回
* false 值。
* 在非阻模式下调用connect( )方法之后,SocketChannel又被切换回了阻模式。那么如果
* 有必要的话,调用线程会阻直到连接建立完成,finishConnect( )方法接着就会返回true
* 值。
* 在初次调用 connect( )或最后一次调用 finishConnect( )之后,连接建立过程已经完成。那么
* SocketChannel 对象的内部状态将被更新到已连接状态,finishConnect( )方法会返回 true
* 值,然后 SocketChannel 对象就可以被用来传输数据了。
* 连接已经建立。那么什么都不会发生,finishConnect( )方法会返回 true 值
*/
// 链接未建立或建立中阻塞任何读写操作
// 方法用作完成链接过程
// 链接被拒绝抛出 java.net.ConnectException: Connection refused
while (!socketChannel.finishConnect()) {
// 链接还未建立成功
System.out.println("loading.....");
}
if (socketChannel.isConnected()) {
// 链接还建立成功
}
// 链接建立成功
System.out.println("success");
}
DatagramChannel
基于UDP/IP协议,一个DatagramChannel可以即是服务端也可以是客户端,且是可以重复使用的。
@Test
public void datagramServer() throws Exception {
DatagramChannel datagramChannel = DatagramChannel.open();
// datagramChannel.configureBlocking(false);
datagramChannel.socket().bind(new InetSocketAddress(9090));
SocketAddress socketAddress = null;
ByteBuffer allocate = ByteBuffer.allocate(10);
allocate.putChar('H');
while (true) {
// 在非阻塞模式下 未接收到消息 返回将为null
// 数据包 可以接受任意链接
socketAddress = datagramChannel.receive(allocate);
if (socketAddress == null) {
// 未接收到消息
continue;
}
// socketAddress 对象值为消息的来源
allocate.flip();
System.out.println(new String(allocate.array(), StandardCharsets.UTF_8));
break;
}
if (datagramChannel.isConnected()) {
// datagram与socketChannel不同,datagram可以重复使用 所以提供了disconnect()方法
// 已链接的datagram可以任意使用通道 read/write
System.out.println("connected");
}
// 给个回复
datagramChannel.send(ByteBuffer.wrap("hello".getBytes(StandardCharsets.UTF_8)), socketAddress);
}
@Test
public void datagramClient() throws Exception {
DatagramChannel datagramChannel = DatagramChannel.open();
// datagram允许不绑定,open()方法在打开一个底层的socket时分配了一个动态端口
// 未绑定的datagram依然可以接受与发送数据包,这个分配的端口是由操作系统决定的
// 发送
datagramChannel.send(ByteBuffer.wrap("hello world".getBytes(StandardCharsets.UTF_8)), new InetSocketAddress("127.0.0.1", 9090));
ByteBuffer allocate = ByteBuffer.allocate(10);
// 这里可以看看有没有回复
SocketAddress socketAddress = datagramChannel.receive(allocate);
if (socketAddress != null) {
allocate.flip();
System.out.println(new String(allocate.array(), StandardCharsets.UTF_8));
}
}
浙公网安备 33010602011771号