java网络NIO的零拷贝

35 篇文章 0 订阅

传统文件io 从磁盘读取一个文件 到通过网络传输出去  经过4次IO复制 3次上下文切换

对其进行优化

经过mmap优化,4次复制 变为3次  上下文切换不变 

由4次复制减少到3次复制 内核切换由4次减少到3次

继续优化 由4次复制减少到2次,内核切换由4次减少到3次

  

一个基本的案例: 

BIO拷贝一个文件的时间


import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *
 */
public class OldIOServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=new ServerSocket(7001);
        while (true){
            Socket socket= serverSocket.accept();
            DataInputStream dataInputStream=new DataInputStream(socket.getInputStream());
            try {
                byte[] bytes=new byte[4096];
                while (true){
                    int read = dataInputStream.read(bytes, 0, bytes.length);
                    if(read==-1){
                        break;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }

}


import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 *
 */
public class OldIOClient {

    public static void main(String[] args) throws IOException {
        Socket socket=new Socket("127.0.0.1",7001);
        InputStream inputStream=new FileInputStream("aa.txt");
        DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
        byte[] buffer=new byte[4096];
        long count=0;
        long readCount=0;

        long startTime=System.currentTimeMillis();
        while ((readCount=inputStream.read(buffer))>0){
            count+=readCount;
            dataOutputStream.write(buffer);
        }

        System.out.println("总共发送了字节数:"+count+"耗时:"+(System.currentTimeMillis()-startTime)/1000);

        dataOutputStream.close();
        socket.close();
        inputStream.close();
    }
}

BIO的拷贝一个大文件的时间



import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 *零拷贝是 没有cpu拷贝
 *  * mmap  4次拷贝--3次   3次切换--3次切换
 *  * sendFile  4次拷贝--3次  3次切换--2次切换
 *  * DMA拷贝  直接内存  从磁盘到内存 使用DMA拷贝  内存到磁盘也是DMA  linux内存到虚拟机 需要cpu拷贝,虚拟机到内存 需要cpu拷贝  所以是4次拷贝
 *  *
 */
public class NewZeroCopyServer {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(7001));

        ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
        while (true){
            SocketChannel socketChannel = serverSocketChannel.accept();
            int readCount=0;
            while (readCount!=-1){
                try {
                    readCount=socketChannel.read(byteBuffer);
                }catch (Exception e){
                    e.printStackTrace();
                }
                byteBuffer.rewind();
            }
        }
    }
}


import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

/**
 *
 */
public class NewZeroCopyClient {

    public static void main(String[] args) throws IOException {

        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.bind(new InetSocketAddress("127.0.0.1",7001));

        //文件输入流
        FileChannel fileChannel=new FileInputStream("aa.txt").getChannel();

        long startTime=System.currentTimeMillis();

        //linux 下 tranferTo 可以将数据拷贝
        //windows下tranferTo 只能拷贝8M的数据,因此需要分段传输
        //transferTo 底层使用了0拷贝
        long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);

        System.out.println("发送总的字节数="+transferCount+"耗时:"+(System.currentTimeMillis()-startTime)/1000);
        fileChannel.close();
        socketChannel.close();

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java中,您可以使用NIO(New I/O)来拷贝文件。NIO提供了更高效的I/O操作方式,特别是在处理大文件时。以下是一个使用NIO拷贝文件的示例代码: ```java import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.channels.FileChannel; public class FileCopyExample { public static void main(String[] args) { String sourceFile = "path/to/source/file.txt"; // 源文件路径 String destinationFile = "path/to/destination/file.txt"; // 目标文件路径 try { // 创建输入流和输出流 FileInputStream fis = new FileInputStream(sourceFile); FileOutputStream fos = new FileOutputStream(destinationFile); // 获取输入流和输出流的通道 FileChannel sourceChannel = fis.getChannel(); FileChannel destinationChannel = fos.getChannel(); // 使用 transferTo() 方法拷贝文件 destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); // 关闭通道和流 sourceChannel.close(); destinationChannel.close(); fis.close(); fos.close(); System.out.println("文件拷贝完成"); } catch (IOException e) { e.printStackTrace(); } } } ``` 在上述示例中,您需要将 `sourceFile` 和 `destinationFile` 的值替换为实际的源文件路径和目标文件路径。代码将打开源文件和目标文件的输入流和输出流,并获取它们的通道。然后,通过调用 `transferFrom()` 方法来拷贝文件数据。最后,关闭通道和流。 请注意,以上代码只是一个简单的示例,没有处理异常情况和错误处理。在实际的应用中,您可能需要添加适当的异常处理和错误检查。 另外,还有其他一些方法可以使用NIO拷贝文件,例如使用 `transferTo()` 方法、使用 `read()` 和 `write()` 方法逐个字节拷贝等。您可以根据自己的需求选择适合的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值