文章目录
- 前言
- 一、主要模块
- 二、使用步骤
- 1.服务器端
- 2.客户端
- 三、NIO零拷贝(推荐)
- 四、NIO另一种copy
- 总结
前言
NIO是JDK1.4版本带来的功能,区别于以往的BIO编程,同步非阻塞极大的节省资源开销,避免了线程切换和上下文切换带来的资源浪费。
一、主要模块
- Selector:选择器,为事件驱动,做中央调度使用,一个选择器可以注册多个channel;
- Channel:通道,信息流通;支持读取和写入数据,一个通道可以有多个Buffer;
- Buffer:缓存区,存放数据,支持读取和写入的切换;
二、使用步骤
1.服务器端
代码如下(示例):
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.Set;
/**
* Create by zjg on 2022/9/11
*/
public class NIOServer {
public static void main(String[] args) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(6666));
Selector selector =Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
if(selector.select(10000)==0){
System.out.println("没有接收到监听事件");
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()){
System.out.println("获取到新的连接");
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ,ByteBuffer.allocate(1024));
}
if(selectionKey.isReadable()){
SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
int read = socketChannel.read(byteBuffer);
if(read==-1){
selectionKey.cancel();
}else{
String req=new String(byteBuffer.array()).trim();
System.out.println("nio客户端说:"+req);
String res= "服务器响应["+LocalDateTime.now().format(DateTimeFormatter.ISO_DATE)+" "+LocalDateTime.now().format(DateTimeFormatter.ISO_TIME)+"]:"+req;
System.out.println(res);
socketChannel.write(ByteBuffer.wrap(res.getBytes()));
}
}
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.客户端
代码如下(示例):
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
/**
* Create by zjg on 2022/9/11
*/
public class NIOClient {
public static void main(String[] args) {
try {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);
if(!socketChannel.connect(inetSocketAddress)){
while (!socketChannel.finishConnect()){
System.out.println("等待连接完成!");
}
}
String message="向往自由!";
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(byteBuffer);
System.out.println("请求完成!");
ByteBuffer allocate = ByteBuffer.allocate(1024);
while (true){
int read = socketChannel.read(allocate);
if(read==0){
continue;
}
System.out.println("---"+new String(allocate.array()).trim());
socketChannel.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、NIO零拷贝(推荐)
package nio;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
/**
* Create by zjg on 2022/9/11
*/
public class NIOZeroCopy {
public static void main(String[] args) {
FileChannel src = null;
FileChannel dest = null;
try {
src=new FileInputStream("2.txt").getChannel();
dest=new FileOutputStream("3.txt").getChannel();
long start = System.currentTimeMillis();
src.transferTo(0,src.size(),dest);
long end = System.currentTimeMillis();
System.out.println("copy完成,共"+src.size()+"byte,用时"+(end-start)+"毫秒");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(src!=null){
try {
src.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(dest!=null){
try {
dest.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
四、NIO另一种copy
package nio;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
/**
* Create by zjg on 2022/9/18
*/
public class NIOTest {
public static void main(String[] args) {
File source=new File("2.txt");
File target=new File("4.txt");
try {
long start = System.currentTimeMillis();
Files.copy(source.toPath(),target.toPath());
long end = System.currentTimeMillis();
System.out.println("copy完成,共"+source.length()+"byte,用时"+(end-start)+"毫秒");
} catch (IOException e) {
e.printStackTrace();
}
}
}
效率稍微慢点,用起来简单。
总结
回到顶部
刚开始写,请大佬指点。