java的 transformTo transformFrom
java是平台无关的,但是JVM是平台相关的。
磁盘上文件拿出来发给用户
最原始的实现(c实现)
内核空间系统调用–上下文切换–直接内存访问DMA 数据**拷贝到内核空间缓冲区(页缓存)–上下文切换–又拷贝**到了用户空间的缓冲区
内核空间系统调用–上下文切换–用户空间 数据**拷贝到内核空间缓冲区(页缓存)–又拷贝**到了网卡的socket缓冲区–上下文切换–返回用户空间
用户空间没有对数据修改

零拷贝(c实现)
完全依赖操作系统的,不会有数据在用户内核之间拷贝
sendfile() 内核空间系统调用–上下文切换–直接内存访问DMA 数据**拷贝到内核空间缓冲区(页缓存)–数据拷贝**到目标socket的缓冲区–缓冲区到DMA网卡发送–上下文切换–返回用户空间

真正的零拷贝(c实现)
文件描述符可以描述数据的一些大小偏移,socket缓存里面只是存这些,
DMA 拷贝内核缓冲区(页缓存)之后–Linux 2.4 之后,文件描述符gather操作,数据不会kernel buffer到socketbuffer,****只有文件描述符的信息(kernel buffer 的内存地址在什么地方;kernel buffer 多长)会到socket buffer里面。原来的数据本身
真正的数据直接去网卡缓冲区



零拷贝案例
服务端读取完就丢弃掉
客户端打印需要的时间
传统方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import java.io.DataInputStream; import java.net.ServerSocket; import java.net.Socket;
public class OldIOServer {
public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8899);
while (true) { Socket socket = serverSocket.accept(); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
try { byte[] byteArray = new byte[4096];
while (true) { int readCount = dataInputStream.read(byteArray, 0, byteArray.length);
if (-1 == readCount) { break; } } } catch (Exception ex) { ex.printStackTrace(); } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.InputStream; import java.net.Socket;
public class OldIOClient {
public static void main(String[] args) throws Exception { Socket socket = new Socket("localhost", 8899);
String fileName = "~/Desktop/spark-2.2.0-bin-hadoop2.7.tgz"; InputStream inputStream = new FileInputStream(fileName);
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
byte[] buffer = new byte[4096]; long readCount; long total = 0;
long startTime = System.currentTimeMillis();
while ((readCount = inputStream.read(buffer)) >= 0) { total += readCount; dataOutputStream.write(buffer); }
System.out.println("发送总字节数: " + total + ", 耗时: " + (System.currentTimeMillis() - startTime));
dataOutputStream.close(); socket.close(); inputStream.close(); } }
|
零拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| 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(8899);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); ServerSocket serverSocket = serverSocketChannel.socket(); serverSocket.setReuseAddress(true); serverSocket.bind(address);
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
while (true) { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(true);
int readCount = 0;
while (-1 != readCount) { try { readCount = socketChannel.read(byteBuffer); } catch (Exception ex) { ex.printStackTrace(); }
byteBuffer.rewind(); } }
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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", 8899)); socketChannel.configureBlocking(true);
String fileName = "~/Desktop/spark-2.2.0-bin-hadoop2.7.tgz";
FileChannel fileChannel = new FileInputStream(fileName).getChannel();
long startTime = System.currentTimeMillis();
long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);
System.out.println("发送总字节数:" + transferCount + ",耗时: " + (System.currentTimeMillis() - startTime));
fileChannel.close(); } }
|
磁盘上文件修改一下发给用户
内存映射
文件内容映射,用户空间直接操作内核空间的文件
java里面的MappedByteBuffer就是这个在支持