####使用阻塞式的NIO的操作
package com.diedline.juc.nio;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
* 使用 NIO完成网络通信的三个核心
* 1. 通道channel : 负责连接
* java.nio.Channel 接口
* | -- SelectableChannel
* | -- SocketChannel
* | -- ServerSocketChannel
* | -- DatagramChannel
*
* | -- Pipe.SinkChannel
* | -- Pipe.SourceChannel
*
* 2. 缓冲区: 负责数据的存取
*
* 3. 选择器Selector 是SelectableChannel 的多路复用器,用于监控SelectableChannel 的IO状况
*
*/
public class TestBlockingNIO {
//客户端
@Test
public void client(){
try {
//获取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
//使用缓存区存取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//先从本地读取文件并发送到服务端
FileChannel fileChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
while (fileChannel.read(byteBuffer) != -1){
//先将缓冲区切换成读数据模式
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
}
socketChannel.close();
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void server(){
try {
//获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//创建一个FileChannel
FileChannel fileChannel = FileChannel.open(Paths.get("2.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//绑定端口号
serverSocketChannel.bind(new InetSocketAddress(9898));
//获取客户端的连接的通道
SocketChannel socketChannel = serverSocketChannel.accept();
//创建一个缓存区
ByteBuffer bf = ByteBuffer.allocate(1024);
//接收客户端的数据并保存到本地
while (socketChannel.read(bf) != -1){
bf.flip();
fileChannel.write(bf);
bf.clear();
}
//关闭对应的通道
fileChannel.close();
serverSocketChannel.close();
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TestNIO
package com.diedline.juc.nio;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class TestBlockingNIO2 {
//客户端
@Test
public void client(){
try {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
FileChannel fileChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
//创建一个缓存
ByteBuffer buf = ByteBuffer.allocate(1024);
//发送数据
while (fileChannel.read(buf) != -1 ){
buf.flip();
socketChannel.write(buf);
buf.clear();
}
//关闭连接进行写入 不关闭通道
socketChannel.shutdownOutput();
//接收服务端的反馈
int len = 0;
while ((len = socketChannel.read(buf)) != -1 ){
buf.flip();
System.out.println(new String(buf.array(),0, len));
buf.clear();
}
socketChannel.close();
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//服务端
@Test
public void server(){
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9898));
SocketChannel channel = serverSocketChannel.accept();
ByteBuffer bf = ByteBuffer.allocate(1024);
FileChannel fileChannel = FileChannel.open(Paths.get("2.png"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);
while (channel.read(bf) != -1){
bf.flip();
fileChannel.write(bf);
bf.clear();
}
//发送反馈给客户端
bf.put("服务端接受客户端的数据成功".getBytes());
bf.flip();
channel.write(bf);
serverSocketChannel.close();
channel.close();
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
####使用非阻塞模式的TcpNIO 如果还需要实现聊天可以使用多线程
package com.diedline.juc.nio;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Date;
import java.util.Iterator;
/**
*
/**
* 使用 NIO完成网络通信的三个核心
* 1. 通道channel : 负责连接
* java.nio.Channel 接口
* | -- SelectableChannel
* | -- SocketChannel
* | -- ServerSocketChannel
* | -- DatagramChannel
*
* | -- Pipe.SinkChannel
* | -- Pipe.SourceChannel
*
* 2. 缓冲区: 负责数据的存取
*
* 3. 选择器Selector 是SelectableChannel 的多路复用器,用于监控SelectableChannel 的IO状况
*/
public class TestNonBlockingNIO {
//客户端
@Test
public void client(){
try {
//获取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
//切换成非阻塞模式
socketChannel.configureBlocking(false);
//分配指定大小的缓存区
ByteBuffer bf = ByteBuffer.allocate(1024);
//发送数据给服务器
bf.put(new Date().toString().getBytes());
bf.flip();
socketChannel.write(bf);
bf.clear();
//关闭通道
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//服务端
@Test
public void server() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//切换成非阻塞模式
serverSocketChannel.configureBlocking(false);
//绑定端口号
serverSocketChannel.bind(new InetSocketAddress(9898));
//获取选择器
Selector selector = Selector.open();
//将通道注册到选择器中,并且指定监听事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//轮询的获取选择器上已经就绪的事件 当大于0就代表有就绪的事件了
while (selector.select() >0){
//获取当前选择器中所有注册的选择键(已注册的监听事件)
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()){
//迭代获取 SelectionKey(准备就绪的事件)
SelectionKey selectionKey = it.next();
//判断具体是什么事件准备就绪
if(selectionKey.isAcceptable()){
//获取serverSocketChannel 所得的SocketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
//切换非阻塞模式
socketChannel.configureBlocking(false);
//将该通道注册到选择器上
socketChannel.register(selector,SelectionKey.OP_READ);
}else if(selectionKey.isReadable()){
//获取当前选择器上读就绪状态的通道 因为默认是selectorChannel 所以要强转
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//读取数据
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = 0;
//如果有数据
while ((len = socketChannel.read(buf)) > 0){
buf.flip();
System.out.println(new String(buf.array(),0,len));
buf.clear();
}
}
//取消选择键SelectionKey
it.remove();
}
}
}
}