Java NIO - 零拷貝

LZC發表於2020-06-16
  1. 使用傳統的IO 方法傳遞一個大檔案

  2. 使用NIO 零拷貝方式傳遞(transferTo)一個大檔案

  3. 看看兩種傳遞方式耗時時間分別是多少

服務端程式碼

public class OldServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(1212);
            System.out.println("服務端啟動已啟動......");
            while (true) {
                // 等待連線
                Socket socket = serverSocket.accept();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 接收訊息
                        try (InputStream inputStream = socket.getInputStream()){
                            byte[] result = new byte[1024];
                            while (true) {
                                int read = inputStream.read(result);
                                if (read == -1) {
                                    break;
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客戶端程式碼

public class OldClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 1212);
        OutputStream outputStream = socket.getOutputStream();
        // 檔案大小為300MB
        File file = new File("D:\\電子書\\深入理解Apache Dubbo與實戰.pdf");
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] buffer = new byte[(int) file.length()];
        long total = 0;
        long startTime = System.currentTimeMillis();
        while (true) {
            long readCount = fileInputStream.read(buffer);
            if (readCount == -1) {
                break;
            }
            total += readCount;
            outputStream.write(buffer);
        }
        outputStream.flush();
        System.out.println("傳送總位元組數: " + total + ", 耗時: " + (System.currentTimeMillis() - startTime));
        fileInputStream.close();

        socket.close();
    }
}

服務端程式碼

public class NewIOServer {
    public static void main(String[] args) throws Exception {

        InetSocketAddress address = new InetSocketAddress(1313);
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(address);
        System.out.println("服務端啟動已啟動......");
        //建立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 作廢
            }
        }
    }
}

客戶端程式碼

public class NewIOClient {
    public static void main(String[] args) throws Exception {

        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost", 1313));
        // 檔案大小為300MB
        String filename = "D:\\電子書\\深入理解Apache Dubbo與實戰.pdf";
        //得到一個檔案channel
        FileChannel fileChannel = new FileInputStream(filename).getChannel();
        //準備傳送
        long startTime = System.currentTimeMillis();
        // 在linux下,一次transferTo 就可以完成傳輸
        //transferTo 底層使用到零拷貝
        // long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);

        //在windows下,一次ransferTo 只能傳送8m , 就需要分段傳輸檔案
        long total = 0;
        long position = 0; // 讀取位置
        while (true) {
            long transferCount = fileChannel.transferTo(position, fileChannel.size(), socketChannel);
            if (transferCount > 0) {
                position = position + transferCount;
                total = total + transferCount;
            } else {
                break;
            }
        }

        System.out.println("傳送的總的位元組數 =" + total + " 耗時:" + (System.currentTimeMillis() - startTime));
        //關閉
        fileChannel.close();

    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章