Простой чат о копировании памяти в сетевом запросе

Java

последовательность

Nuggets — это платформа, которую я только что обнаружил.Изначально некоторые учебные заметки были записаны в Youdao, потому что уценка поддерживается с обеих сторон, и теперь я планирую поделиться некоторыми организованными заметками. Эта статья предназначена в основном для того, чтобы кратко рассказать о копиях памяти в сетевых запросах.

Схема процесса передачи данных в сетевом запросе

Тип передачи данных один (чтение)

Эта модель передачи данных точно такая же, как традиционный ввод-вывод для сетевой связи.Данные копируются и контекст переключается несколько раз в пользовательском пространстве (память JVM) и пространстве ядра.Когда нет бизнес-обработки данных, такое копирование становится совершенно ненужным.

Второй тип передачи данных (sendFile)

Эта модель передачи данных используется NIO для связи по сети.Это зависит от того, поддерживает ли операционная система эту операцию на ядре (четвертый процесс на рисунке).По сравнению с первой эта модель сокращает ненужные данные в два раза. процесс копирования между пользовательским пространством и ядром.

Третий тип передачи данных (поддерживает агрегированный sendFile)

Отсюда мы можем обнаружить, что эта реальная реализациянулевая копия, эта модель передачи зависит от того, поддерживает ли операционная система такого рода операции на ядре (4 процесса на рисунке). 4 процесса на рисунке трудно понять. Давайте раскроем тайны четырех процессов.

Четвертый процесс фактически заключается в добавленииStr информации о файле (адрес файла, размер и т. д.) в ядре к буферу Sokcet, чтобы в буфере Sokcet было мало информации, а затем используйте Gather для объединения двух буферов перед протоколом. двигатель передает.

Тип передачи данных четыре (mmap, в этой статье не представлен)

Код

Модель один (БИО)

/**
 * @Author CoderJiA
 * @Description TransferModel1Client
 * @Date 23/2/19 下午3:01
 **/
public class TransferModel1Client {

    private static final String HOST = "localhost";
    private static final int PORT = 8899;
    private static final String FILE_PATH = "/Users/coderjia/Documents/gradle-5.2.1-all.zip";
    private static final int MB = 1024 * 1024;

    public static void main(String[] args) throws Exception{
        Socket socket = new Socket(HOST, PORT);
        InputStream input = new FileInputStream(FILE_PATH);
        DataOutputStream output = new DataOutputStream(socket.getOutputStream());
        byte[] bytes = new byte[MB];
        long start = System.currentTimeMillis();
        int len;
        while ((len = input.read(bytes)) != -1) {
            output.write(bytes, 0, len);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start) + "ms");
        output.close();
        input.close();
        socket.close();
    }
}
/**
 * @Author CoderJiA
 * @Description TransferModel1Server
 * @Date 23/2/19 下午3:01
 **/
public class TransferModel1Server {

    private static final int PORT = 8899;
    private static final int MB = 1024 * 1024;

    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(PORT);
        for (;;) {
            Socket socket = serverSocket.accept();
            DataInputStream input = new DataInputStream(socket.getInputStream());
            byte[] bytes = new byte[MB];
            for (;;) {
                int readSize = input.read(bytes, 0, MB);
                if (-1 == readSize) {
                    break;
                }
            }
        }
    }
}

Модель II (НИО)

/**
 * @Author CoderJiA
 * @Description TransferModel2Client
 * @Date 23/2/19 下午3:36
 **/
public class TransferModel2Client {

    private static final String HOST = "localhost";
    private static final int PORT = 8899;
    private static final String FILE_PATH = "/Users/coderjia/Documents/gradle-5.2.1-all.zip";

    public static void main(String[] args) throws Exception {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress(HOST, PORT));
        socketChannel.configureBlocking(true);
        FileChannel fileChannel = new FileInputStream(FILE_PATH).getChannel();
        long start = System.currentTimeMillis();
        fileChannel.transferTo(0, fileChannel.size(), socketChannel);
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start) + "ms");
        fileChannel.close();
    }

}
/**
 * @Author CoderJiA
 * @Description TransferModel2Server
 * @Date 23/2/19 下午3:36
 **/
public class TransferModel2Server {

    private static final int PORT = 8899;
    private static final int MB = 1024 * 1024;

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

        InetSocketAddress address = new InetSocketAddress(PORT);

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.setReuseAddress(true);
        serverSocket.bind(address);

        ByteBuffer byteBuffer = ByteBuffer.allocate(MB);
        for (;;) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(true);
            int readSize = 0;
            while (-1 != readSize) {
                readSize = socketChannel.read(byteBuffer);
                byteBuffer.rewind();
            }

        }

    }
}

fileChannel.transferTo(0, fileChannel.size(), socketChannel)

Примечание к документации для метода transferto: этот метод потенциально гораздо более эффективен, чем простой цикл, который читает из этого канала и записывает в целевой канал.Многие операционные системы могут передавать байты непосредственно из кеша файловой системы в целевой канал, фактически не копируя их.

Простое понимание этого предложения заключается в том, что этот метод более эффективен, чем традиционный простой опрос (имеется в виду процесс копирования в IO).Метод копирования tranferto зависит от базовой операционной системы.В настоящее время многие операционные системы поддерживают процесс копирования. как вторая модель. В ядре версии 2.4 дескриптор буфера сокета был изменен, чтобы соответствовать этим требованиям, что в Linux называется нулевым копированием. Такой подход не только сокращает количество переключений контекста, но и полностью устраняет операции копирования данных из процессора.

Сравнение производительности

На той же машине результаты теста в той же среде показаны на рисунке.

Адрес справочной статьи

у-у-у. Краткое описание.com/afraid/oh 9 422586…

Адрес источника

Github.com/coder домой 061 ...