File file = new File("test.txt");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
byte[] arr = new byte[(int) file.length()];
raf.read(arr);
Socket socket = new ServerSocket(8080).accept();
socket.getOutputStream().write(arr);
传统IO 进行四次拷贝,三次切换(仅仅是读写)
mmap 优化
sendFile 优化1
所谓零拷贝是操作系统角度看,是没有CPU拷贝
sendFile 优化
小结:
这里其实有 一次cpu 拷贝
kernel buffer -> socket buffer
但是,拷贝的信息很少,比如
lenght , offset , 消耗低,可以
忽略
零拷贝的再次理解
零拷贝案例-Server
package com.atguigu.nio.zerocopy;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
//服务器
public class NewIOServer {
public static void main(String[] args) throws Exception {
InetSocketAddress address = new InetSocketAddress(7001);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(address);
//创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
int readcount = 0;
while (-1 != readcount) {
try {
readcount = socketChannel.read(byteBuffer);
}catch (Exception ex) {
// ex.printStackTrace();
break;
}
//
byteBuffer.rewind(); //倒带 position = 0 mark 作废
}
}
}
}
零拷贝案例-CLient
package com.atguigu.nio.zerocopy;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
public class NewIOClient {
public static void main(String[] args) throws Exception {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 7001));
String filename = "protoc-3.6.1-win32.zip";
//得到一个文件channel
FileChannel fileChannel = new FileInputStream(filename).getChannel();
//准备发送
long startTime = System.currentTimeMillis();
//在linux下一个transferTo 方法就可以完成传输
//在windows 下 一次调用 transferTo 只能发送8m , 就需要分段传输文件, 而且要主要
//传输时的位置 =》 课后思考...
//transferTo 底层使用到零拷贝
long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);
System.out.println("发送的总的字节数 =" + transferCount + " 耗时:" + (System.currentTimeMillis() - startTime));
//关闭
fileChannel.close();
}
}

NIO零拷贝关键方法
将此通道的文件中的字节传输到给定的可写字节通道。
尝试读取从该通道文件中给定位置开始的count个字节,并将它们写入目标通道。此方法的调用可能会也可能不会传输所有请求的字节;是否这样做取决于通道的性质和状态。如果此通道的文件从给定位置开始包含少于count个字节,或者如果目标通道是非阻塞的并且其输出缓冲区中的空闲字节少于count个,则传输的字节数少于请求的字节数。
此方法不会修改此通道的位置。如果给定位置大于文件的当前大小,则不传输任何字节。如果目标通道有一个位置,则从该位置开始写入字节,然后该位置增加写入的字节数。
这种方法可能比从该通道读取并写入目标通道的简单循环更有效。许多操作系统可以直接将字节从文件系统缓存传输到目标通道,而无需实际复制它们。
参数:
position – 文件中开始传输的位置;必须是非负数
count – 要传输的最大字节数;必须是非负数
target – 目标通道
返回值:
实际传输的字节数,可能为零
抛出:
IllegalArgumentException – 如果参数的先决条件不成立
NonReadableChannelException – 如果未打开此通道进行读取
NonWritableChannelException – 如果没有打开目标通道进行写入
ClosedChannelException – 如果此通道或目标通道已关闭
AsynchronousCloseException – 如果另一个线程在传输过程中关闭任一通道
ClosedByInterruptException – 如果另一个线程在传输过程中中断当前线程,从而关闭两个通道并设置当前线程的中断状态
IOException – 如果发生其他一些 I/O 错误
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;